【回眸】技术干货——Linux 内核 (十七) 之 多线程编程 下
前言
前面介绍了互斥锁,本篇博文介绍死锁及其他多线程遇到的情况。
什么情况会造成死锁
死锁指的是两个或两个以上的运算单元(进程、线程或协程),互相持有对方所需的资源,导致它们都无法向前推进,从而导致永久阻塞的问题就是死锁。
线程条件控制实现线程同步
初始化线程条件控制
int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr);
也可以使用静态初始化:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
互斥锁也可以静态初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
阻塞条件线程
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex); int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const struct timespec* abstime);
备注:abstime 参数指的是绝对时间
pthread_cond_wait() 函数可以永久阻塞线程,直到条件变量成立的那一刻;pthread_cond_timedwait() 函数只能在 abstime 参数指定的时间内阻塞线程,超出时限后,该函数将重新对互斥锁执行“加锁”操作,并解除对线程的阻塞,函数的返回值为 ETIMEDOUT。
解除条件线程阻塞
int pthread_cond_signal(pthread_cond_t* cond); int pthread_cond_broadcast(pthread_cond_t* cond);
pthread_cond_signal() 函数至少解除一个线程的“被阻塞”状态,如果等待队列中包含多个线程,优先解除哪个线程将由操作系统的线程调度程序决定;
pthread_cond_broadcast() 函数可以解除等待队列中所有线程的“被阻塞”状态。
有可能解除阻塞后还是无法执行,可能存在的原因是互斥锁锁定了,等待互斥锁释放资源后即可继续执行。
销毁条件线程
int pthread_cond_destroy(pthread_cond_t *cond);
多线程编程
thread9.c(死锁 2个锁产生冲突)
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <stdlib.h> pthread_mutex_t mutex; pthread_mutex_t mutex2; pthread_attr_t attr; pthread_attr_t attr2; int g_data = 0; void *func1(void *arg){ pthread_mutex_lock(&mutex); sleep(1); pthread_mutex_lock(&mutex2); while(1){ printf("t1:%d\n",g_data++); sleep(1); if (g_data == 4){ pthread_mutex_unlock(&mutex); //printf("t1 Quit.=============================\n"); pthread_exit(NULL); exit(0); } } } void *func2(void *arg){ printf("t2:%ld thread is created.\n",(unsigned long)pthread_self()); printf("t2:param is %d\n",*((int *)arg)); while(1){ pthread_mutex_lock(&mutex2); sleep(1); pthread_mutex_lock(&mutex); printf("t2:%d\n",g_data); g_data++; pthread_mutex_unlock(&mutex); sleep(1); } } int main(){ int ret; int param =100; pthread_t t1; pthread_t t2; pthread_mutex_init(&mutex,NULL); pthread_mutex_init(&mutex2,NULL); ret = pthread_create(&t1,NULL,func1,(void *)¶m); if(ret == 0){ printf("main:Create t1 sucess.\n"); } ret = pthread_create(&t2,NULL,func2,(void *)¶m); if(ret == 0){ printf("main:Create t2 sucess.\n"); } printf("mainID:%ld .\n",(unsigned long)pthread_self()); printf("main:g_data = %d.\n",g_data); pthread_join(t1,NULL);//等待 pthread_join(t2,NULL);//等待 pthread_attr_destroy(&attr); pthread_attr_destroy(&attr2); return 0; }
thread10.c(条件线程)
#include <stdio.h> #include <pthread.h> #include <unistd.h> pthread_mutex_t mutex; pthread_cond_t cond; int g_data = 0; void *func1(void *arg){ pthread_mutex_lock(&mutex);//保证t1优先 while(1){ pthread_cond_wait(&cond,&mutex);//等待 printf("t1:%d\n",g_data++); printf("t1 Run.=============================\n"); sleep(1); g_data = 0; } } void *func2(void *arg){ printf("t2:%ld thread is created.\n",(unsigned long)pthread_self()); printf("t2:param is %d\n",*((int *)arg)); while(1){ pthread_mutex_lock(&mutex); printf("t2:%d\n",g_data); g_data++; if(g_data == 3) { pthread_cond_signal(&cond);//触发 } pthread_mutex_unlock(&mutex); sleep(1); } } int main(){ int ret; int param =100; pthread_t t1; pthread_t t2; pthread_mutex_init(&mutex,NULL); pthread_cond_init(&cond,NULL); ret = pthread_create(&t1,NULL,func1,(void *)¶m); if(ret == 0){ printf("main:Create t1 sucess.\n"); } ret = pthread_create(&t2,NULL,func2,(void *)¶m); if(ret == 0){ printf("main:Create t2 sucess.\n"); } printf("mainID:%ld .\n",(unsigned long)pthread_self()); printf("main:g_data = %d.\n",g_data); pthread_join(t1,NULL);//等待 pthread_join(t2,NULL);//等待 pthread_attr_destroy(&mutex); pthread_cond_destroy(&cond); return 0; }
后记碎碎念
Linux内核是一个系列,可以点击专栏查看同系列的其他文章,希望能帮到屏幕前的每一位应届生往届生,该博文最初发表在CSDN上。
#校招求职有谈薪空间吗##找工作前vs找工作后的心路变化##租房前辈的忠告##职场中你干过哪些“蠢”事##26届秋招投递记录#本专栏助应届生从物联网小白成长为企业争抢的技术人才,聚焦三大核心技术:传感器应用(环境监测)、嵌入式开发(STM32/Arduino)、通信协议(LoRa/NB-IoT/MQTT),配合10+实战项目(如智能温湿度监控系统)积累项目经验。覆盖智能硬件、工业物联网、智能家居领域岗位需求,解析企业招聘技术重点与面试题,帮电子、计算机、自动化等专业学生构建知识体系,提前锁定名企Offer!