【学习嵌入式day-26-线程间通信】
遍历找到/home/linux/Music目录下的指定文件
#include "../head.h"int is_target_file(char *pfilename)
{//定义一个指针,找到'.'的位置,如果指针为NULL,则没有找到'.'char *lastname = NULL;while(*pfilename != '\0'){if('.' == *pfilename){lastname = pfilename;//指针走到‘.’的位置}pfilename++;}if(NULL == lastname){return 0;}/*//定义一个指针,先走到末尾'\0'的位置,当指针不等于'.'的时候进入循环,//指针减减,往前走,走到'.'的位置,退出循环char *ptmp = NULL;ptmp = pfilname + strlen(pfilename);while(ptmp >= pfilename && ptmp != '\0'){ptmp--;}*/if(0 == strcmp(lastname, ".mp3") || 0 == strcmp(lastname, ".mp4") ||0 == strcmp(lastname, ".avi") || 0 == strcmp(lastname, ".rmvb") || 0 == strcmp(lastname, ".flv") || 0 == strcmp(lastname, ".wma") ||0 == strcmp(lastname, ".txt")){return 1;}return 0;
}//遍历home目录,找到/home/linux/music
int listdir(char *dirpath)
{//opendir打开/home目录DIR *dp = NULL;struct dirent *pp = NULL;char tmpbuff[1096] = {0};dp = opendir(dirpath);if(NULL == dp){perror("fail to opendir");return -1;}//readdir读目录while(1){pp = readdir(dp);if(NULL == pp){break;}if('.' == pp->d_name[0]){continue;}sprintf(tmpbuff, "%s/%s", dirpath, pp->d_name);if(is_target_file(pp->d_name)){printf("%s\n", tmpbuff);}}closedir(dp);return 0;
}int main(void)
{listdir("/home/linux/Music");return 0;
}
创建四个进程
#include "../head.h"//线程参数类型
typedef struct pthread_arg
{pthread_t tid; //存放线程IDchar 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){sleep(parg->sleeptime);printf("%s正在执行\n", parg->threadname);}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;
}
线程属性
线程创建pthread_create(),第二个参数可以传属性参数(加入属性、分离属性)
线程属性
- 加入属性:线程技术需要pthread_join手动回收
- 分离属性:线程结束后系统自动回收线程空间
函数接口
pthread_attr_init(初始化)
pthread_attr_setdetachstate(设置属性)
pthread_attr_destroy
区别
- 分离属性:
- 分离属性可以等到线程结束后,操作系统自动回收空间
- 不需要调用pthread_join回收线程空间
- 加入属性:
- 可以回收线程结束的状态
- 可以完成线程间的同步
#include "../head.h"void *thread1(void *arg)
{sleep(5);printf("线程1结束\n");return NULL;
}
void *thread2(void *arg)
{printf("线程2结束\n");return NULL;
}int main(void)
{pthread_t tid[2];int i = 0;void*(*p[2])(void *) = {thread1, thread2};pthread_attr_t attr;pthread_attr_init(&attr); //初始化//设置分离属性pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);for(i = 0; i < 2; i++){//第二个参数传attr参数pthread_create(&tid[i], &attr, p[i], NULL);}pthread_attr_destroy(&attr);while(1){}return 0;
}
线程间通信
概念
- 多个线程间传递信息
方式
采用全局变量
- 原因
- 进程是操作系统资源分配的最小单元
- 每个进程空间是独立的,包含文本段+数据段(全局变量)+系统数据段
- 一个进程间的多个线程独享栈空间,文本段、数据段、堆区在进程中是共享的
- 多线程同时操作共享空间会引发资源竞争,需要加上互斥锁解决资源竞争问题
- 原因
互斥锁
不能决定执行线程的先后顺序
概念
- 解决资源竞争的一种方式
- 只能加锁一次,加锁期间不能再次加锁,也不能强制占有一个已经加锁的锁资源,必须等待资源释放,也就是解锁后才能继续操作该锁
- 加锁和解锁中间的代码称为临界代码,也成为临界区
- 只能防止多个线程对资源的竞争,不能决定代码的先后执行顺序
- 原子操作:CPU执行原子操作时无法切换调度任务
使用方式:
- 定义互斥锁(全局变量)
- 对锁初始化
- 操作全局资源前先加锁
- 如果加锁成功,则完成对全局资源操作
- 如果加锁失败,则表示有人占用资源,必须等待其余人释放锁资源才能加锁成功
- 直到加锁成功使用该全局资源
函数接口
- phread_mutex_init
- phread_mutex_lock
- phread_mutex_unlock
- phread_mutex_destroy
#include "../head.h"int value = 100;
int num1 = 0;
int num2 = 0;
pthread_mutex_t lock;void *thread1(void *arg)
{while(1){pthread_mutex_lock(&lock);num1 = value;num2 = value;pthread_mutex_unlock(&lock);value++;}return NULL;
}
void *thread2(void *arg)
{while(1){pthread_mutex_lock(&lock);if(num1 != num2){printf("num1 = %d, num2 = %d\n", num1, num2);}pthread_mutex_unlock(&lock);}return NULL;
}int main(void)
{pthread_t tid1;pthread_t tid2;pthread_mutex_init(&lock, NULL);pthread_create(&tid1, NULL, thread1, NULL);pthread_create(&tid2, NULL, thread2, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_mutex_destroy(&lock);return 0;
}
死锁
概念
- 多线程由于加锁解锁错误,导致程序无法继续向下运行的状态,称为死锁状态
死锁产生的四个必要条件
- 互斥条件
- 不可剥夺条件
- 请求保持条件
- 循环等待条件
避免死锁:
- 加锁顺序保持一致
- 使用pthread_mutex_trylock 替换 pthread_mutex_lock
信号量
概念
- 信号量是一种资源
- 只能完成四种操作:初始化、销毁、申请、释放
- 如果信号量资源数为0,申请资源会被阻塞等待,直到占用资源的任务释放资源,资源数部位0时,才能申请到资源并继续向下执行
- 释放资源不会阻塞
函数接口
- sem_init
- sem_destroy
- sem_wait
- 释放信号量会让信号量资源数-1
- 如果信号量资源数为0,则会阻塞等待,直到有任务释放资源,才能拿到资源并继续向下执行
- sem_post
#include "../head.h"sem_t nsem;int main(void)
{//参数1:要初始化的信号量地址//参数2: 为0,线程间共享;非0,进程间共享//参数3:信号量的初始值,表示可用资源数量sem_init(&nsem, 0, 2);sem_wait(&nsem);printf("获得资源\n");sem_wait(&nsem);printf("获得资源\n");sem_post(&nsem);printf("释放资源\n");sem_wait(&nsem);printf("获得资源\n");sem_destroy(&nsem);return 0;
}