嵌入式学习day29-线程

day28练习

1.找到并打印指定目录下的音视频文件

#include "../head.h"

int is_mediafile(char *pfilename)
{
    char *ptmp = NULL;

    ptmp = pfilename + strlen(pfilename);
    while (ptmp >= pfilename && *ptmp != '.')
    {
        ptmp--;
    }

    if (0 == strcmp(ptmp, ".mp3") || 0 == strcmp(ptmp, ".mp4") || 0 == strcmp(ptmp, ".avi")
        || 0 == strcmp(ptmp, ".rmvb") || 0 == strcmp(ptmp, ".flv") || 0 == strcmp(ptmp, ".wma"))
    {
        return 1;
    }

    return 0;
}

int print_mediafile(char *pmediadir)
{
    DIR *dp = NULL;
    struct dirent *pp = NULL;

    dp = opendir(pmediadir);
    if (NULL == dp)
    {
        perror("fail to opendir");
        return -1;
    }

    while (1)
    {
        pp = readdir(dp);
        if (NULL == pp)
        {
            break;
        }

        if ('.' == pp->d_name[0])
        {
            continue;
        }

        if (is_mediafile(pp->d_name))
        {
            printf("%s\n", pp->d_name);
        }
    }
    
    closedir(dp);

    return 0;
}

int main(void)
{
    print_mediafile("/home/linux/Music");

    return 0;
}

2.创建4个线程任务

普通方法:

#include "../head.h"

void *thread_collect(void *arg)
{
    printf("采集线程开始执行\n");

    while (1)
    {
        printf("采集线程正在执行\n");
        sleep(1);
    }

    return NULL;
}

void *thread_record(void *arg)
{
    printf("存储线程开始执行\n");

    while (1)
    {
        printf("存储线程正在执行\n");
        sleep(2);
    }

    return NULL;
}

void *thread_display(void *arg)
{
    printf("显示线程开始执行\n");

    while (1)
    {
        printf("显示线程正在执行\n");
        sleep(5);
    }

    return NULL;
}

void *thread_log(void *arg)
{
    printf("日志线程开始执行\n");

    while (1)
    {
        printf("日志线程正在执行\n");
        sleep(10);
    }

    return NULL;
}

int main(void)
{   
    int i = 0;
    pthread_t tid[4];
    void *(*p[4])(void *) = {thread_collect, thread_display, thread_record, thread_log};

    for (i = 0; i < 4; i++)
    {
        pthread_create(&tid[i], NULL, p[i], NULL);
    }
    
    for (i = 0; i < 4; i++)
    {
        pthread_join(tid[i], NULL);
    }

    return 0;
}

传参方法:

#include "../head.h"

/* 线程参数类型 */
typedef struct pthread_arg
{
    pthread_t tid;                  //存放线程ID
    char threadname[32];            //线程名称
    int sleeptime;                  //睡眠时间
}pthread_arg_t;

void *thread(void *arg)
{
    pthread_arg_t *parg = arg;
    printf("%s(TID:%#lx)开始执行\n", parg->threadname, parg->tid);

    while (1)
    {
        printf("%s正在执行\n", parg->threadname);
        sleep(parg->sleeptime);
    }

    return NULL;
}

int main(void)
{   
    int i = 0;
    pthread_arg_t args[4] = {
        {0, "采集线程", 1},
        {0, "存储线程", 2},
        {0, "显示线程", 5},
        {0, "日志线程", 10},
    };

    for (i = 0; i < 4; i++)
    {
        pthread_create(&args[i].tid, NULL, thread, &args[i]);
    }
    
    for (i = 0; i < 4; i++)
    {
        pthread_join(args[i].tid, NULL);
    }

    return 0;
}

线程属性

线程属性:

  • 加入属性:线程结束需要pyhread_join手动回收
  • 分离属性:线程结束后系统自动回收线程空间

函数接口:

pthread_attr_init

原型:int pthread_attr_init(pthread_attr_t *attr);
功能:
    线程属性初始化
参数:
    attr:线程属性空间的首地址

pthread_attr_setdetachstate

原型:int pthread_attr_setdetachstate(pthread_attr_t *attr,int
detachstate);
功能:
    将线程属性设置为分离属性
参数:
    attr:线程属性空间的首地址
    detachstate:属性
    PTHREAD_CREATE_DETACHED 分离属性
    PTHREAD_CREATE_JOINABLE 加入属性

pthread_attr_destroy

原型:int pthread_attr_destroy(pthread_attr_t *attr);
功能:
    线程属性销毁
参数:
    attr:线程属性空间的首地址

区别:

分离属性:

        线程结束后,操作系统自动回收空间

        不需要手动调用pthread_join回收线程空间

加入属性:

        可以回收到线程结束的状态

        可以完成线程间的同步


线程间通信:

概念:
  • 多个线程间传递信息

方式:

  • 采用全局变量
    • 原因:
      • 进程是操作系统资源分配的最小单元
      • 每个进程空间独立的,包含文本段 + 数据段(全局变量)+ 系统数据段
      • 一个进程中的多个线程独享栈空间,文本段、数据段、堆区进程多线程共享
  • 注意:
    • 多线程同时操作共享空间会引发资源竞争,需要加入互斥锁解决资源竞争问题

互斥锁:

概念:
  • 解决资源竞争的一种方式,可以看成是一种资源。
  • 只能加锁一次,加锁期间不能再次加锁,也能强制占有一个已经加锁的锁资源,必须等待锁资源释放,也就是解锁后才能继续操作该锁
  • 加锁和解锁中间的代码称为临界代码,也称为临界区
  • 只能防止多个线程对资源的竞争,不能决定代码的先后执行顺序
  • 原子操作:CPU执行原子操作时无法切换调度任务

使用方式:

  1. 定义互斥锁(全局变量)
  2. 对锁初始化
  3. 操作全局资源前先加锁
  4. 如果加锁成功则完全对全局资源操作
  5. 如果加锁失败则表示有人占用资源,必须等待其余人释放锁资源才能加锁成功
  6. 直到加锁成功使用该全局资源

函数接口:

pthread_mutex_int
原型:int pthread_mutex_init(pthread_mutex_t *restrict mutex,const
pthread_mutexattr_t *restrict attr);
功能:
    初始化互斥锁
参数:
    mutex:互斥锁空间首地址
    attr:属性,默认为NULL
返回值:
    成功返回0
    失败返回-1
pthread_mutex_lock
原型:int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:
    互斥锁加锁
pthread_mutex_unlock
原型:int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:
互斥锁解锁
pthread_mutex_destroy
原型:int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:
    互斥锁销毁

死锁

概念:

多线程由于加锁解锁错误导致程序无法继续向下运行的状态称为死锁状态,简称为死锁

死锁产生的四个必要条件:
  1. 互斥条件
  2. 不可剥夺条件
  3. 请求保持条件
  4. 循环等待条件

如何避免死锁:
  1. 加锁顺序保持一致
  2. 使用pthread_mutex_trylock替换pthread_mutex_lock

信号量

概念:
  • 信号量是一种资源
  • 信号量只能完成四种操作:初始化、销毁、申请、释放
  • 如果信号量资源数为0,申请资源会阻塞等待,直到占用资源的任务释放资源,资源数不为0时才能申请到资源并继续向下执行
  • 释放资源不会阻塞

函数接口:

sem_init
原型:int sem_init(sem_t *sem,int pshared,unsigned int value);
功能:
    初始化信号量
参数:
    sem:信号的空间的首地址
    pshared:
        0:一个进程的多个线程间共享
        非0:多个进程间共享
    value:
        初始化的资源的值
返回值:
    成功返回0
    失败返回-1

sem_destroy
原型:int 5em_destroy(sem_t *sem);
功能:
    销毁信号量
参数:
    sem:信号量空间的首地址
返回值:
    成功返回0
    失败返回-1
sem_wait
原型:int sem_wait(sem_t *sem);
功能:
    申请信号量
参数:
    sem:信号量空间首地址
返回值:
    成功返回0
    失败返回-1
  • 申请信号量会让信号量资源数-1
  • 如果信号量资源数为0,则会阻塞等待,直到有任务释放资源,才能拿到资源并继续向下执行
sem_post
原型:int sem_post(sem_t *sem);
功能:
    释放信号量
参数:
    sem:信号量空间首地址
返回值:
    成功返回0
    失败返回-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值