线程的同步与互斥

多个线程同时访问共享数据时可能会发生冲突,比如两个线程同时把一个全局变量加1,结果可能不是我们所期待的:

我们看这段代码的执行结果:

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

static int g_count=0;

void *thread(void *arg)

{

int index=0;

int tmp=0;

while(index++<5000)

{

tmp=g_count;

printf("this is thread %d,count is :%d\n",(int)arg,tmp);

g_count=tmp+1;

}

}

int main()

{

pthread_t tid1,tid2;

pthread_create(&tid1,NULL,thread,(void*)1);

pthread_create(&tid2,NULL,thread,(void*)2);

pthread_join(tid1,NULL);

pthread_join(tid2,NULL);

printf("the final value is %d\n",g_count);

return 0;

}

我们看它的执行结果:

我们创建了两个线程,各自把全局变量g_count加了5000次,结果理论上应该是10000,但其实不然,每次运行的结果都不一样,证明访问冲突了。为了解决这个问题,我们需引入互斥锁。获得锁的线程可以完成“读--修改--写”的操作,然后释放锁给其他线程,没有获得锁的线程只能等待,而不能访问共享数据,这样“读--修改--写”散步操作就成了原子操作,要么都执行,要么都不执行,不会执行到中间而被打断,这样就如我们所期待的了。

pthread_mutex_init函数对mutex做初始化,它可以被pthread_mutex_destroy销毁。如果mutex变量是静态分配的,也可以用宏定义PTHREAD_MUTEX_INITIALIZER来初始化,相当于pthread_mutex_init初始化并且attr参数为NULL。

加锁和解锁所需函数:

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,失败返回错误号。

一个线程可以调用int pthread_mutex_lock获得mutex,如果这时候另一个线程已经调用int pthread_mutex_lock获得了该mutex,则当前线程需要挂起等待,直到另一个线程调用pthread_mutex_unlock释放mutex,当前线程被唤醒,才能获得该mutex并继续执行。

如果一个线程既想获得锁,又不想挂起等待,可以调用 pthread_mutex_trylock,如果mutex已经被另一个线程获得,则这个函数会返回EBUSY,而不会使线程挂起等待。

知道这些的话,我们重新修改以上代码:

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

static int g_count=0;

pthread_mutex_t mutex_lock=PTHREAD_MUTEX_INITIALIZER;

void *thread(void *arg)

{

int index=0;

int tmp=0;

while(index++<5000)

{

pthread_mutex_lock(&mutex_lock);

tmp=g_count;

printf("this is thread %d,count is :%d\n",(int)arg,tmp);

g_count=tmp+1;

pthread_mutex_unlock(&mutex_lock);

}

}

int main()

{

pthread_t tid1,tid2;

pthread_create(&tid1,NULL,thread,(void*)1);

pthread_create(&tid2,NULL,thread,(void*)2);

pthread_join(tid1,NULL);

pthread_join(tid2,NULL);

printf("the final value is %d\n",g_count);

return 0;

}

运行结果如下:

我们可以看到,经过我们加锁后,最后value的值是我们所期待的10000,加锁成功,成功实现了两个线程的互斥运行。

死锁产生的原因及四个必要条件

所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,他们都将无法再向前推进。

产生死锁的主要原因有:

1.系统资源不足;

2.进程运行推进的顺序不合适;

3.资源分配不当等;

如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就降低,否则,就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。

产生死锁的四个必要条件:

1.互斥条件:一个资源每次只能被一个进程使用;

2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;

3.不剥夺条件:进程已获得的资源,在使用完之前,不能强行剥夺;

4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系;

以上是产生死锁的四个必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

处理死锁的基本方法:

1.预防死锁:

该方法是通过设置某些限制条件,去破坏产生死锁四个必要条件中的一个或几个条件,来预防发生死锁。

2.避免死锁

不需事先采取各种限制措施去破坏产生死锁的四个必要条件,而是在资源的动态分配过程中,用某种方法去防止系统进入不安全状态,从而避免发生死锁。

3.检测死锁

这种方法不需事先采取任何限制措施,也不必检查系统是否已经进入不安全区,而是允许系统在运行过程中发生死锁。但可以通过系统所设置的检测机构,及时的检测死锁的发生,并精确的确定与死锁有关的进程资源,然后采取适当措施,从系统中将已发生的死锁清除掉。

4.解除死锁

这是与检测死锁相配套的一种措施。当检测到发生死锁时,需将进程从死锁状态中解脱出来。常用的实施方法是撤消或挂起一些进程,以便回收一些资源,再将这些资源分配给已处于阻塞状态的进程,使之转为就绪状态,一边继续运行。

死锁的解除与预防:

理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大程度的避免,预防和解除死锁。所以在系统设计,进程调度等方面注意如何不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占用系统资源。此外,也要防止进程在处于等待状态的情况下占用资源。因此,对资源的分配要给与合理的规划。

转载于:https://blog.51cto.com/10706198/1764798

线程的同步与互斥,死锁相关推荐

  1. 线程的同步与互斥:互斥锁

    什么是线程的同步与互斥? 互斥:指在某一时刻指允许一个进程运行其中的程序片,具有排他性和唯一性. 对于线程A和线程B来讲,在同一时刻,只允许一个线程对临界资源进行操作,即当A进入临界区对资源操作时,B ...

  2. Linux多线程编程---线程间同步(互斥锁、条件变量、信号量和读写锁)

    本篇博文转自http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/ Linux下提供了 ...

  3. linux线程间同步(1)互斥锁与条件变量

    线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点.linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量以及读写锁. 互斥锁(mutex) 互斥锁,是一种信 ...

  4. 进程与线程(同步、互斥、通信方式等)

    一.并发 并行 同步 异步 多线程的区别(引用:https://blog.csdn.net/cqkxboy168/article/details/9026205) 1. 并发:在操作系统中,是指一个时 ...

  5. 操作系统之信号量机制以及使用信号量实现进程(线程)同步和互斥

    1.同步和互斥: 同步(直接制约关系):指的是完成同一任务的伙伴进程间,因需要协调它们的工作而等待.传递信息等.(z(进程1)和m(进程2)需要完成买东西的任务,z把钱给了m,m才能去买东西.) 互斥 ...

  6. 【Linux系统编程】线程同步与互斥:POSIX无名信号量

    信号量概述 信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问. 编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 ...

  7. 吃字母------线程同步与互斥的学习

    线程的同步与互斥的实战----吃字母 希望能给你一些启发: 我们在资源输入数据,下面的两个缓冲区,通过线程获取资源的数据,吃货A-D 抢 两个缓冲区的数据 并放入对应的数据栏中. 例如: 解决思想和方 ...

  8. 50.Linux 线程三 同步

    Linux系统中常用实现线程同步的方式有三种,分别为互斥锁.条件变量与信号量. 下面将对这三种方式逐一进行讲解. 4.1 互斥锁 使用互斥锁实现线程同步时,系统会为共享资源添加一个称为互斥锁的标记,防 ...

  9. Linux系统编程----16(线程同步,互斥量 mutex,互斥锁的相关函数,死锁,读写锁)

    同步概念 所谓同步,即同时起步,协调一致.不同的对象,对"同步"的理解方式略有不同.如,设备同步,是指在两 个设备之间规定一个共同的时间参考:数据库同步,是指让两个或多个数据库内容 ...

最新文章

  1. 使用 Sphinx 撰写技术文档并生成 PDF 总结
  2. nodejs 2017
  3. tomcat(4)Tomcat的默认连接器
  4. hadoop 多机全分布式安装步骤(虚拟机1master+2slave)
  5. Centos6配置samba服务器并批量添加用户和文件夹
  6. Python学习笔记(四十)— 内置模块(9)HTMLParser
  7. AcWing 1934. 贝茜放慢脚步(二路归并)
  8. 关于数据分析部门组织架构的探讨
  9. django Form 效验
  10. Android--hardwareAccelerated 硬件加速详解 android:largeHeap=true
  11. 奥威尔:老大哥在看着你-软件公司十诫
  12. ArcGIS单波段提取
  13. 【Python】改变对象的字符串显示
  14. 大规模分布式深度网络
  15. 华为荣耀手机 (HUAWEI Honor V9) USB 调试 - ADB 调试
  16. UVA(WA) 10815 安迪的第一个字典
  17. 计算机输入法如何显示在桌面快捷方式,电脑桌面输入法图标不见了怎么办
  18. 在Arcmap中,如何“让标注和注记的字体,以及符号化后的符号大小随着比例尺大小的变换而变换”???
  19. [python]Crypto.Util.number ,long_to_bytes函数说明
  20. 讲讲BW/4 HANA和BW on HANA的区别

热门文章

  1. 检索 COM 类工厂中 CLSID 为{00024500-0000-0000-C000-000000000046} 的组件时失败
  2. apipost使用mock随机获取多组数据中的一组数据进行测试
  3. 01-07 Linux三剑客-grep
  4. tenda 服务器无法打开网页,Win7系统网页打不开qq能上怎么办? | 192路由网
  5. 广西大学计算机英语复试的内容,广西大学计算机专业的研究生复试时
  6. Python网络爬虫系列(一)
  7. 身为前端工程师,对你来说,你认为最重要的是什么?
  8. 自学转行成前端工程师,三面拿下字节跳动offer
  9. 详解+G - 数据结构实验之栈与队列七:出栈序列判定
  10. 计算机导论声明型摆设,《计算机导论作业-论文排档》.doc