当前位置: 首页 > news >正文

线程同步——互斥量解锁、解锁

类似与进程间通信信号量的加锁解锁。

对互斥量进行加锁后,任何其他试图在此对互斥量加锁的线程都会被阻塞,直到当前线程释放该互斥锁。如果释放互斥锁时有多个线程被阻塞,所有在该互斥锁上的阻塞线程都会变成可运行状态,第一个变为可运行状态的线程可以对互斥量加锁,其他线程将会看到互斥量依旧被锁住,只能回去等待它重新变为可用。在这种方式下,每次只有一个线程可以向前运行。

在设计时需要规定所有的线程必须遵守相同的数据访问规则,只有这样,互斥机制才能正常工作。如果允许其中的某个线程在没有得到锁的情况下也可以访问共享资源,那么即使其他的线程在使用共享资源前都获取了锁,也还是会出现数据不一致的问题。

互斥变量用pthread_mutex_t数据类型表示。在使用互斥变量前必须对它进行初始化,可以把它置为常量。

PTREAD_MUTEX-INITIALIZWE(只对静态分配的互斥量),也可以通过调用pthread_mutex_init函数对其进行初始化。如果动态的分配互斥量(例如调用malloc),那么在释放内存前需要调用pthread_mutex_destory。

创建互斥锁

函数原型

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

参数

pthread_mutex_t *restrict mutex:锁的地址。

onst pthread_mutexattr_t *restrict attr:锁的属性,可以是NULL,默认属性创建锁

返回值

若成功返回0,否则返回错误编号

销毁互斥锁

函数原型

int pthread_mutex_destroy(pthread_mutex_t *mutex);

参数

pthread_mutex_t *mutex:锁的地址。

返回值

若成功返回0,否则返回错误编号

加锁、解锁

函数原型:

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

返回值:

若成功返回0,否则返回错误编号

  如果线程不希望被阻塞,它可以使用pthread_mutex_trylock尝试对互斥量进行加锁。如果调用pthread_mutex_trylock时互斥量处于未锁住状态,那么pthread_mutex_trylock将锁住互斥量,不会出现阻塞并返回0,否则pthread_mutex_trylock就会失败,不能锁住互斥量,而返回EBUSY。

示例1:

在前面一节,提出了一个问题,怎么保证t1线程先运行,我们可以把g_data作为一个互斥量,对它进行加锁、解锁就可以实现。

#include <stdio.h>
#include <pthread.h>
//int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//int pthread_mutex_destroy(pthread_mutex_t *mutex);
//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 g_data=0;pthread_mutex_t mutex;void *func1(void *arg)
{int i;pthread_mutex_lock(&mutex);for(i=0;i<3;i++){printf("t1:%ld thread is creart\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int *)arg));sleep(1);}pthread_mutex_unlock(&mutex);
}void *func2(void *arg)
{pthread_mutex_lock(&mutex);printf("t2:%ld thread is creart\n",(unsigned long)pthread_self());printf("t2:param is %d\n",*((int *)arg));pthread_mutex_unlock(&mutex);
}int main()
{int param=100;char *pret=NULL;int ret1;int ret2; pthread_t t1;pthread_t t2;pthread_mutex_init(&mutex,NULL);ret1=pthread_create(&t1, NULL,func1, (void *)&param);ret2=pthread_create(&t1, NULL,func2, (void *)&param);if(ret1 == 0){printf("main:create t1 successed\n");}if(ret2 == 0){printf("main:create t2 successed\n");}printf("main:%ld\n",(unsigned long)pthread_self());pthread_join(t1,NULL);printf("main: t1 quit:%s\n",pret);pthread_join(t2,NULL);printf("main: t2 quit:%s\n",pret);pthread_mutex_destroy(&mutex);return 0;
}

上面代码运行的结果来看,无论运行多少次代码,都是t1线程运行完毕后,t2线程才运行。main函数不在t1后运行的原因时,main线程并没有参与互斥锁的加锁解锁。

示例2:互斥锁限制共享资源的访问

前面一节还提到了一个问题,如何保证g_data=3 时 t1 线程退出

#include <stdio.h>
#include <pthread.h>
//int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); 
//int pthread_mutex_destroy(pthread_mutex_t mutex);
//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 g_data=0;void *func1(void *arg)
{printf("t1:%ld thread is creart\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int *)arg));pthread_mutex_lock(&mutex);while(1){printf("t1:%d\n",g_data++);sleep(1);if(g_data==3){printf("==================\n");pthread_mutex_unlock(&mutex);pthread_exit(NULL);}}}void *func2(void *arg)
{printf("t2:%ld thread is creart\n",(unsigned long)pthread_self());printf("t2:param is %d\n",*((int *)arg));while(1){printf("t2:%d\n",g_data);pthread_mutex_lock(&mutex);g_data++;pthread_mutex_unlock(&mutex);sleep(1);}
}int main()
{int param=100;char *pret=NULL;int ret1;int ret2;pthread_t t1;pthread_t t2;pthread_mutex_init(&mutex,NULL);ret1=pthread_create(&t1, NULL,func1, (void *)&param);ret2=pthread_create(&t1, NULL,func2, (void *)&param);if(ret1 == 0){printf("main:create t1 successed\n");}if(ret2 == 0){printf("main:create t2 successed\n");}printf("main:%ld\n",(unsigned long)pthread_self());while(1){printf("main:%d\n",g_data);sleep(1);}pthread_join(t1,NULL);pthread_join(t2,NULL);pthread_mutex_destroy(&mutex);return 0;
}

因为在g_data到达3之前,t1至少会被运行一次,所以可以运行t1时加锁,直到g_data=3,t1退出在解锁就可以实现。可以看到以上戴拿运行情况,只要运行到t1线程,g_data=3时就退出,再去运行t2和main。

相关文章:

  • Python教程---Python交互界面
  • idea 配置checkstyle全过程
  • 在PyCharm中直接启动mitmproxy并自动打开关闭系统代理
  • 采用XML作为GUI描述语言
  • 本地idea远程调试服务器程序
  • 隐私安全|隐私安全已从国家法律法规转向商业企业应用,如何理解以及落地建设,相信大家正在经历隐私安全的困扰
  • 性能优于BERT的FLAIR:一篇文章入门Flair模型
  • MapReduce WordCount程序实践(IDEA版)
  • 使用vscode开发uniapp项目常用的辅助插件,提升开发效率
  • github使用教程
  • 【Redis】Redis实现分布式锁
  • COCOS2DX3.17.2 Android升级targetSDK30问题解决方案
  • 【技术干货】开源库 Com.Gitusme.Net.Extensiones.Core 的使用
  • c++类和对象
  • 算法与数据结构之链表
  • Angular 2 DI - IoC DI - 1
  • dva中组件的懒加载
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • JAVA_NIO系列——Channel和Buffer详解
  • JavaScript的使用你知道几种?(上)
  • JS函数式编程 数组部分风格 ES6版
  • tab.js分享及浏览器兼容性问题汇总
  • Web设计流程优化:网页效果图设计新思路
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 反思总结然后整装待发
  • 分类模型——Logistics Regression
  • 基于web的全景—— Pannellum小试
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 微信小程序填坑清单
  • 在electron中实现跨域请求,无需更改服务器端设置
  • 转载:[译] 内容加速黑科技趣谈
  • 关于Android全面屏虚拟导航栏的适配总结
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #基础#使用Jupyter进行Notebook的转换 .ipynb文件导出为.md文件
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (二)正点原子I.MX6ULL u-boot移植
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (小白学Java)Java简介和基本配置
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • (转)JAVA中的堆栈
  • .htaccess配置重写url引擎
  • .NET开发不可不知、不可不用的辅助类(一)
  • .NET框架设计—常被忽视的C#设计技巧
  • .net图片验证码生成、点击刷新及验证输入是否正确
  • .sh
  • @Repository 注解
  • [ CTF ] WriteUp- 2022年第三届“网鼎杯”网络安全大赛(朱雀组)
  • [Android] 修改设备访问权限
  • [C++数据结构](31)哈夫曼树,哈夫曼编码与解码
  • [CSS] - 修正IE6不支持position:fixed的bug
  • [CSS3备忘] transform animation 等
  • [elastic 8.x]java客户端连接elasticsearch与操作索引与文档
  • [GXYCTF2019]禁止套娃