linux下线程间通讯--互斥锁 1.互斥锁简介 在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为 互斥锁 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
互斥锁(mutex)是在原子操作api的基础上实现的信号量行为。互斥锁不能进行递归锁定或解锁,能用于交互上下文但是不能用于中断上下文,同一时间只能有一个任务持有互斥锁,而且只有这个任务可以对互斥锁进行解锁。
互斥锁是一种简单的加锁的方法来控制对共享资源的存取,当多个线程访问公共资源时,为了保证同一时刻只有一个线程独占资源,就可以通过互斥锁加以限制,在一个时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程才能够对共享资源进行操作。若其他线程希望上锁一个已经上锁了的互斥锁,则该线程就会挂起,直到上锁的线程释放掉互斥锁为止。
2.互斥锁相关函数 在posix thread中定义有一套专门用于线程同步的mutex函数。可以通过静态和动态两种方式创建互斥锁。
互斥锁有三个类型可供选择:
pthread_mutex_timed_np普通锁(默认锁):
当一个线程加锁以后,其余请求锁的线程将形成一个阻塞等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
pthread_mutex_recursive_np嵌套锁:
允许同一个线程对同一个锁成功获得多次,并通过多次unlock 解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
嵌套锁对同一线程可以重复上锁成功,对不同线程不能重复上锁。
嵌套锁在同一线程中重复上锁,需要重复解锁,否则其它线程将阻塞。
pthread_mutex_errorcheck_np检错锁:
如果同一个线程请求同一个锁,则返回 edeadlk,否则与普通锁类型动作相同。 这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。
检错锁的主要特点就是: 同一个线程无法多次重复进行加锁, 第一次获取锁成功后, 没有解锁的情况下, 如果继续获取锁将不会阻塞, 会返回一个错误值(35)。
动态方式初始化互斥锁:int pthread_mutex_init(pthread_mutex_t *restrict mutex,constpthread_mutexattr_t *restrict attr); attr填null表示使用默认属性,创建普通锁。//静态方式初始化互斥锁pthread_mutex_t mutex = pthread_mutex_initializer;//互斥锁上锁,多次请求则会阻塞int pthread_mutex_lock(pthread_mutex_t *mutex);//互斥锁上锁,多次请求不会阻塞,会返回上锁失败错误信息int pthread_mutex_trylock(pthread_mutex_t *mutex);//互斥解锁int pthread_mutex_unlock(pthread_mutex_t *mutex);//销毁互斥锁int pthread_mutex_destroy(pthread_mutex_t *mutex); 3.互斥锁编程 3.1练习1 1.创建1个线程,子线程先打印10遍hello,world,然后主线程再打印5遍”12346”,按次顺序循环50次。
#include #include #include /*1.创建1个线程,子线程先打印10遍hello,world,然后主线程再打印5遍”12346”,按次顺序循环50次。*/pthread_mutex_t mutex = pthread_mutex_initializer;//静态初始化互斥锁1pthread_mutex_t mutex2 = pthread_mutex_initializer;//静态初始化互斥锁2void *pth_work(void *arg){ int i,j; for(i=0;i<50;i++) { pthread_mutex_lock(&mutex); printf(-----------子线程第%d遍-----------\n,i); for(j=0;j<10;j++) { printf(hello,world\n); } pthread_mutex_unlock(&mutex2); }}int main(){ int i=0,j; pthread_t pthid; pthread_mutex_lock(&mutex2); /*创建子线程*/ pthread_create(&pthid,null,pth_work,null);//创建线程 pthread_detach(pthid); for(i=0;i<50;i++) { pthread_mutex_lock(&mutex2);//互斥锁上锁 printf(-----------主线程第%d遍-----------\n,i); for(j=0;j<5;j++)//主线程打印 { printf(123456\n); } pthread_mutex_unlock(&mutex); } pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&mutex2);} 3.2练习2 2.创建3线程,线程1打印a,线程2打印b,线程3打印c,按照abc顺序输出10遍。
#include #include #include /*2.创建3线程,线程1打印a,线程2打印b,线程3打印c,按照abc顺序输出10遍。*/pthread_mutex_t mutex = pthread_mutex_initializer;//静态初始化互斥锁1pthread_mutex_t mutex2 = pthread_mutex_initializer;//静态初始化互斥锁2pthread_mutex_t mutex3 = pthread_mutex_initializer;//静态初始化互斥锁3void *pth_work(void *arg){ int cnt=(int *)arg; //printf(cnt=%d\n,cnt); for(int i=0;i<10;i++) { if(cnt==0)//线程1 { pthread_mutex_lock(&mutex); printf(a); pthread_mutex_unlock(&mutex2); } if(cnt==1)//线程2 { pthread_mutex_lock(&mutex2); printf(b); pthread_mutex_unlock(&mutex3); } if(cnt==2)//线程3 { pthread_mutex_lock(&mutex3); printf(c); fflush(stdout);//刷新缓冲区 pthread_mutex_unlock(&mutex); } }}int main(){ int i=0; pthread_t pthid[3]; pthread_mutex_lock(&mutex2); pthread_mutex_lock(&mutex3); /*创建3个子线程*/ for(i=0;i<3;i++) { pthread_create(&pthid[i],null,pth_work,(void *)i); } /*等待线程结束*/ for(i=0;i<3;i++) { pthread_join(pthid[i],null); } printf(\n所有子线程结束,程序退出!\n); pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&mutex2); pthread_mutex_destroy(&mutex3);} 运行效果:
[wbyq@wbyq ubuntu]$ ./app abcabcabcabcabcabcabcabcabcabc所有子线程结束,程序退出!
IBM宣布推出世界首个通用量子计算机 量子云服务也不远了
车载OLED显示模块ESD/EOS防护方案
非蜂窝5G,物联网的下一块拼图?
三星推出两款高端智能显示器 M7和 M5,运行智能电视系统的显示器
区块链与数据隐私怎样做可以兼容
Linux下线程间通讯--互斥锁
低调的哪吒汽车何以紧追明星造车新势力?
残疾人士福音:德国成功研发“读心机器手”
【新品推荐】氧气变送器OMD-150
Virtex UltraScale FPGA发货同时,赛灵思还新增加了另一款器件VU190 FPGA
VCS/XRUN如何创建一个非UVM的简单仿真环境?
诺顿运算放大器的典型应用电路
昕诺飞智能互连道路照明系统及LED路灯已突破两万套
音圈模组加持的阿尔法蛋AI词典笔X10
无线MCU调试技巧汇总
废弃电池再循环负极材料(RAM)的循环利用研究
红外技术解决音频无线传输难题
微机保护装置是什么及其在电力系统中的作用
VR,AR,MR目前无处不在,正在从休闲游戏世界进入商业企业世界
你知道TinyML运行效能谁说了算吗?