学习嵌入式第三十天
文章目录
- 进程和线程(续)
- 线程
- 1.线程传参
- 2.线程属性
- 3.线程间通信
- 1.概念
- 2.方式
- 3.互斥锁
- 4.死锁
- 5.信号量
- 习题
进程和线程(续)
线程
1.线程传参
-
使用第四个参数实现对线程内部的传参
代码实现:
#include <stdio.h> #include <string.h> #include <dirent.h> #include <sys/types.h> #include <pthread.h> #include <unistd.h>typedef struct pthread_arg{pthread_t tid;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; }
2.线程属性
- 加入属性:线程结束需要pthread_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:线程属性空间的首地址
3.线程间通信
1.概念
- 多个线程间传递信息
2.方式
采用全局变量
- 原因:进程是操作系统分配的最小单元;每个进程空间独立,包含文本段,数据段(全局变量),系统数据段;一个进程中的多个线程独享栈空间,而文本段,数据段,堆区进程多线程共享
- 多线程同时操作共享空间会引发资源竞争,需要加上互斥锁解决资源竞争问题
3.互斥锁
-
概念
-
解决资源竞争的一种方式,可以看成是一种资源
-
只能加锁一次,加锁期间不能再次加锁,也不能强制占有一个已经加锁的锁资源,必须等待锁资源释放,也就是解锁后才能继续操作该锁
-
加锁和解锁中间的代码称为临界代码,也称为临界区
-
只能防止多个线程对资源的竞争,不能决定代码的先后执行顺序
-
原子操作:CPU执行原子操作时无法切换调度任务
-
-
使用方式
- 定义互斥锁
- 对锁初始化
- 操作全局资源前先加锁
- 如果加锁成功则完成对全局资源操作
- 如果加锁失败则表示有人占用资源,必须等待其余人释放锁资源才能加锁成功
- 直到加锁成功使用该全局资源
-
函数接口
-
pthread_mutex_init
原型: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); 功能:互斥锁销毁
-
4.死锁
- 概念
- 多线程由于加锁解锁不合理导致程序无法继续向下运行的状态
- 产生的条件
- 互斥条件
- 不可剥夺条件
- 请求保持条件
- 循环等待条件
- 避免死锁
- 加锁顺序保持一致
- 使用pthread_mutex_trylock替换pthread_mutex_lock
5.信号量
-
概念
- 信号量是一种资源
- 信号量只能完成初始化,销毁,申请,释放四种操作
- 如果信号量资源数为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 sem_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
-
习题
编写三个线程任务,线程一循环打印‘A’,线程一循环打印‘B’,线程一循环打印‘C’,要求打印出的字符顺序总为ABC
代码实现:
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
#include<semaphore.h>sem_t sem_wa;
sem_t sem_wb;
sem_t sem_wc;void *thread1(void *arg){while(1){sem_wait(&sem_wa);printf("A\n");sem_post(&sem_wb);}return NULL;
}
void *thread2(void *arg){while(1){sem_wait(&sem_wb);printf("B\n");sem_post(&sem_wc);}return NULL;
}
void *thread3(void *arg){while(1){sem_wait(&sem_wc);printf("C\n");sem_post(&sem_wa);}return NULL;
}int main(void){pthread_t tid1;pthread_t tid2;pthread_t tid3;sem_init(&sem_wa,0,1);sem_init(&sem_wb,0,0);sem_init(&sem_wc,0,0);pthread_create(&tid1,NULL,thread1,NULL);pthread_create(&tid2,NULL,thread2,NULL);pthread_create(&tid3,NULL,thread3,NULL);pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);sem_destroy(&sem_wa);sem_destroy(&sem_wb);sem_destroy(&sem_wc);return 0;
}