linux c编程:线程互斥二 线程死锁
死锁就是不同的程序在运行时因为某种原因发生了阻塞,进而导致程序不能正常运行。阻塞程序的原因通常都是由于程序没有正确使用临界资源。
我们举个日常生活中的例子来比喻死锁。我们把马路上行驶的汽车比作运行着的程序,把马路比作临界资源,如果有两辆汽车相互碰撞,就会把车停在马路上,这样的话他们一直占用着马路这个临界资源。其它的汽车不能正常通过马路,于是整条路上的汽车都无法在马路上正常行驶,马路也被汽车堵的水泄不通。整个交通都瘫痪了,这就是“死锁”。造成死锁的原因就是发生车祸的汽车占用了马路这种临界资源,以至于其它汽车无法在马路上正常行驶。
在实际的程序中造成死锁的原因有两种:
1 同一个线程对已经加锁的互斥量再次加锁;
2 线程A对互斥量一加锁,同时等待互斥量二被解锁;而此时,线程B对互斥量二加锁,同时等待互斥量一被解锁;
首先来看第一种现象:
int value=0;
pthread_mutex_t mutex_value_tmp1=PTHREAD_MUTEX_INITIALIZER;
void read_data(){
printf("data=%d\n",value);
printf("end reading data\n");
}
void threading_func1(){
int i=0;
int res=0;
pthread_t thread_id;
thread_id=pthread_self();
printf("Thread id :%d\n",thread_id);
while(i<4){
res=pthread_mutex_lock(&mutex_value_tmp1); #第一次加锁
if (res !=0){
printf("thread mutex failed\n");
}
read_data();
res=pthread_mutex_lock(&mutex_value_tmp1); #第二次加锁
if (res !=0){
printf("thread mutex failed\n");
}
res=pthread_mutex_unlock(&mutex_value_tmp1); #释放锁;
printf("res=%d\n",res);
if (res !=0){
printf("mutex unlock failed\n");
}
Sleep(2000);
}
pthread_exit((void *)2);
}
结果执行如下:
当线程2再次执行的时候,由于无法获取锁,因此发生死锁

这种情况下为了避免阻塞。需要用到pthread_mutex_tryloc。
函数pthread_mutex_trylock是pthread_mutex_lock的非阻塞版本。如果mutex参数所指定的互斥锁已经被锁定的话,调用pthread_mutex_trylock函数不会阻塞当前线程,而是立即返回一个值来描述互斥锁的状况。将上面代码中的pthread_mutex_lock全部替换为pthread_mutex_trylock。在来看下运行结果:
每当重复加锁的时候都会发生加锁失败,但是不会发生死锁。

下面来看下第二种情况:
代码如下:
int value=0;
pthread_mutex_t mutex_value_tmp1=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_value_tmp2=PTHREAD_MUTEX_INITIALIZER;
void read_data(){
printf("data=%d\n",value);
printf("end reading data\n");
}
void write_data(){
value+=1;
printf("data=%d\n",value);
printf("end writing data\n");
}
void threading_func1(){
int i=0;
int res=0;
pthread_t thread_id;
thread_id=pthread_self();
printf("Thread id :%d\n",thread_id);
while(i++<4){
res=pthread_mutex_trylock(&mutex_value_tmp1);
if (res !=0){
printf("thread mutex1 failed\n");
}
read_data();
res=pthread_mutex_trylock(&mutex_value_tmp2);
if (res !=0){
printf("thread mutex2 failed\n");
}
res=pthread_mutex_unlock(&mutex_value_tmp2);
if (res !=0){
printf("mutex2 unlock failed\n");
}
res=pthread_mutex_unlock(&mutex_value_tmp1);
if (res !=0){
printf("mutex1 unlock failed\n");
}
Sleep(2000);
}
pthread_exit((void *)2);
}
void threading_func2(){
int i=0;
int res=0;
pthread_t thread_id;
thread_id=pthread_self();
printf("Thread id :%d\n",thread_id);
while(i++<4){
res=pthread_mutex_lock(&mutex_value_tmp2);
if (res !=0){
printf("thread mutex2 failed\n");
}
write_data();
res=pthread_mutex_lock(&mutex_value_tmp1);
if (res !=0){
printf("thread mutex1 failed\n");
}
res=pthread_mutex_unlock(&mutex_value_tmp1);
if (res !=0){
printf("mutex1 unlock failed\n");
}
res=pthread_mutex_unlock(&mutex_value_tmp2);
if (res !=0){
printf("mutex2 unlock failed\n");
}
Sleep(2000);
}
pthread_exit((void *)2);
}
int main()
{
pthread_t tid1,tid2;
int res;
void *tret;
pthread_mutex_init(&mutex_value_tmp1,NULL);
pthread_mutex_init(&mutex_value_tmp2,NULL);
pthread_create(&tid1,NULL,threading_func1,NULL);
pthread_create(&tid2,NULL,threading_func2,NULL);
pthread_join(tid1,&tret);
printf("thread 1 exit code %ld\n",(long)tret);
pthread_join(tid2,&tret);
printf("thread 2 exit code %ld\n",(long)tret);
res=pthread_mutex_destroy(&mutex_value_tmp1);
if (res!=0){
printf("mutex can't be destroyed");
}
return 0;
}
运行结果如下:从下面的程序运行结果中可以看到,线程1锁住了互斥量一,同时等待互斥量二;而线程2锁住了互斥量二,同时等待互斥量一。这样便造成了死锁,进而引起了程序运行错误。在写代码的时候应该避免这类用法

linux c编程:线程互斥二 线程死锁的更多相关文章
- linux高级编程基础系列:线程间通信
linux高级编程基础系列:线程间通信 转载:原文地址http://blog.163.com/jimking_2010/blog/static/1716015352013102510748824/ 线 ...
- python 之 并发编程(守护线程与守护进程的区别、线程互斥锁、死锁现象与递归锁、信号量、GIL全局解释器锁)
9.94 守护线程与守护进程的区别 1.对主进程来说,运行完毕指的是主进程代码运行完毕2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕详细解释:1.主 ...
- Linux系统编程(28)——线程间同步
多个线程同时访问共享数据时可能会冲突,这跟前面讲信号时所说的可重入性是同样的问题.比如两个线程都要把某个全局变量增加1,这个操作在某平台需要三条指令完成: 从内存读变量值到寄存器 寄存器的值加1 将寄 ...
- Linux系统编程(27)——线程控制
进程在各自独立的地址空间中运行,进程之间共享数据需要用mmap或者进程间通信机制,那么如何在一个进程的地址空间中执行多个线程呢.有些情况需要在一个进程中同时执行多个控制流程,这时候线程就派上了用场,比 ...
- linux网络编程之简单的线程池实现
转眼间离15年的春节越来越近了,还有两周的工作时间貌似心已经不在异乡了,期待与家人团聚的日子,当然最后两周也得坚持站好最后一班岗,另外期待的日子往往是心里不能平静的,越是想着过年,反而日子过得越慢,于 ...
- linux网络编程-一个简单的线程池(41)
有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带来的开销,我们可以使用线程池 1.线程池拥有若干个线程,是线程的集合,线程池中的线程数目有严格的要求,用于执行大量的相对短 ...
- linux线程篇 (二) 线程的基本操作
线程 进程 标识符 pthread_t pid_t 获取ID pthread_self() getpid() 创建 pthread_create() fork 销毁 pthread_exit() ...
- Python之多线程:线程互斥与线程同步
一.锁在多线程中的使用:线程互斥 lock = threading.Lock()#创建一个锁对象 1.with lock: pass 和进程使用的方式相同 2.控制线程结束的时间 通过一个全局变量 ...
- linux c编程:互斥锁
们常说互斥锁保护临界区,实际上是说保护临界区中被多个线程或进程共享的数据.互斥锁保证任何时刻只有一个线程在执行其中的代码. 互斥锁具有以下特点: ·原子性:把一个互斥锁定义为一个原子操作,这意味着操作 ...
随机推荐
- 质量平台建设之Mock平台
转载:http://blog.csdn.net/spark2008/article/details/51372913 基于目前系统越来越多,在项目开发过程中,减少各模块之间的开发依赖,另保证各个系统模 ...
- 页面加载后累加,自加1&&判断数字是否为两位数
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 【C/C++学院】0828-数组与指针/内存分配/数据结构数组接口与封装
[送给在路上的程序猿] 对于一个开发人员而言,可以胜任系统中随意一个模块的开发是其核心价值的体现. 对于一个架构师而言,掌握各种语言的优势并能够运用到系统中.由此简化系统的开发,是其架构生涯的第一步. ...
- Archlinux: 优化触摸板配置
在逛 Archlinuxcn BBS 时看到这个帖子: fcitx 输入法看不到选词,上面键盘也不见了! 等待妹子的 依云 提到了 infinality, 并且给出了这个链接: fix-infinal ...
- springMVC 【@response 返回对象自动变成json并且防止乱码】 & 【配置支持实体类中的@DateTimeFormat注解】
在springmvc的配置文件中加上这一段即可 <bean class="org.springframework.web.servlet.mvc.annotation.Annotati ...
- scikit-learn---PCA(Principle Component Analysis)---KNN(image classifier)
摘要:PCA为非监督分类方法,常用于数据降维.为监督分类数据预处理,本例采用PCA对人脸特征提取先做降维处理,然后使用KNN算法对图片进行分类 ##1.PCA简介 设法将原来变量重新组合成一组新的互相 ...
- git revert 后悔了 还原修改前的版本 + git 常用命令
昨天手残 然后在GitHub for windows 上点了revert 然后就给重置了 更手残的是又给同步了 . 但是 GitHub 会保留之前的版本 . 只要删掉本次修改就可. 解决方案: g ...
- Java利用Axis远程调用WebService接口
准备工作: 主要依赖的包: 1.axis.jar 官网:http://axis.apache.org/axis/ 2.jaxrpc.jar 下载地址:http://www.java2s.com/Cod ...
- [译]NeHe教程 - 你的第一个多边形
原文: Your First Polygon 在第一节中我讲解了如何创建OpenGL窗体.本节我会讲解如何创建三角形和四边形.我们会用GL_TRIANGLES来创建三角形,用GL_GUADS创建四边形 ...
- 【Python + Selenium】之JS定位总结
感谢:小琰子 Python+Selenium 脚本中的一些js的用法汇总: 1.滚动条 driver.set_window_size(500,500) js = "window.scroll ...