0基础学会 线程同步(互斥锁pthread_mutex)(内附C语言源码)_pthread_mutex_lock-程序员宅基地

技术标签: 进程  高并发  线程  Linux系统编程  面试必备  互斥锁  

目录

一、为什么要学习线程同步?

二、用程序来分析如果不使用线程同步会有什么危害。

三、解决方法

一、为什么要学习线程同步?

线程的主要优势在于,能够通过全局变量来共享信息。不过这种便携的共享是要付出代价的,必须确保多个线程不会同时修改同一个变量,或者某一线程不会读取正在由其他线程修改的变量。

临界区是指访问某一共享资源的代码片段,并且这段代码的执行应为原子操作(这个程序是最小单位,不能被再次分割,不能被其他进程中断),也就是同时访问同一共享资源的其他线程不应中断该片段的执行。

线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作,而其他线程则处于等待状态。

二、用程序来分析如果不使用线程同步会有什么危害。

举例:三个线程卖5000张票。

  1 #include <stdio.h>
  2 #include <pthread.h>
  3 #include <unistd.h>
  4 int ticket=500;
  5 void *sellticket(void *arg)
  6 {
  7         //买票 ticket时临界资源
  8         while(ticket>0)
  9         {
 10                 sleep(1);
 11                 printf("%ld 卖出了第%d张票\n",pthread_self(),ticket);
 12                 ticket--;//线程并发去执行 抢CPU执行资格
 13         }
 14         return NULL;
 15 }
 16 int main()
 17 {
 18         pthread_t tid1,tid2,tid3;
 19         pthread_create(&tid1,NULL,sellticket,NULL);
 20         pthread_create(&tid2,NULL,sellticket,NULL);
 21         pthread_create(&tid3,NULL,sellticket,NULL);
 22 //回收子进程
 23         pthread_join(tid1,NULL);
 24         pthread_join(tid2,NULL);
 25         pthread_join(tid3,NULL);
 26 
 27         return 0;
 28 
 29 }

运行结果: 

 发现了没,竟然出现了“卖出了第-1张票”,我明明循环的是“ticket>0”怎么会出现-1呢?而且还会出现多个线程卖同一张票的情况,这都是没有进行线程同步时出现的问题。

三、解决方法

采用互斥量:

        为避免线程更新共享变量时出现问题,可以使用互斥量(mutex)来确保同时仅有一个线程可以访问某项共享资源。可以使用互斥量来保证对任意共享资源的原子访问。

        互斥量有两种状态:已锁定(locked)和未锁定(unlocked)。任何时候,至多只有一个线程可以锁定该互斥量。试图对已经锁定的某一互斥量再次加锁,将可能阻塞线程或者报错失败,具体取决于加锁时使用的方法。

        一旦线程锁定互斥量,随即成为该互斥量的所有者,只有所有者才能给互斥量解锁。一般情况下,对每一共享资源(可能由多个相关变量组成)会使用不同的互斥量,每一线程在访问同一资源时将采用如下协议:

        1、针对共享资源锁定互斥量

        2、访问共享资源

        3、对互斥量解锁 

接下来介绍相关的API

pthread_mutex_t //互斥量的类型
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);//初始化互斥量
    -参数:
        -mutex:需要初始化的互斥量变量
        -attr:互斥量相关的属性,NULL
     -restrict:C语言修饰符,被修改的指针,不能由另外的一个指针进行操作
        -pthread_mutex_t *restrict mutex=xxx;
        -pthread_mutex_t *mutex1=mutex;
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);//解锁
        

我把刚才的买票程序进行一个改进

  1 #include <stdio.h>
  2 #include <pthread.h>
  3 #include <unistd.h>
  4 int ticket=800;
  5 //在全局区创建一个互斥量,这样大家就都能访问
  6 pthread_mutex_t mutex;
  7 
  8 void *sellticket(void *arg)
  9 {
 10         //买票 ticket时临界资源
 11         while(1)
 12         {
 13                 //加锁
 14                 pthread_mutex_lock(&mutex);
 15                 if(ticket>0)
 16                 {
 17                         usleep(5000);
 18                         printf("%ld 卖出了第%d张票\n",pthread_self(),ticket);
 19                         ticket--;//线程并发去执行 抢CPU执行资格
 20                 }
 21                 else
 22                 {
 23                         pthread_mutex_unlock(&mutex);
 24                         break;
 25                 }
 26                 pthread_mutex_unlock(&mutex);
 27         }//临界区结束
 28         //解锁
 29         return NULL;
 30 }
 31 int main()
 32 {
 33         //初始化互斥量
 34         pthread_mutex_init(&mutex,NULL);
 35         //创建3个子线程
 36         pthread_t tid1,tid2,tid3;
 37         pthread_create(&tid1,NULL,sellticket,NULL);
 38         pthread_create(&tid2,NULL,sellticket,NULL);
 39         pthread_create(&tid3,NULL,sellticket,NULL);
 40 
 41         pthread_join(tid1,NULL);
 42         pthread_join(tid2,NULL);
 43         pthread_join(tid3,NULL);
 44         //释放互斥量
 45         pthread_mutex_destroy(&mutex);
 46         return 0;
 47 
 48 }

我们在设置票数的时候尽量设置的大一些,因为根据自身电脑性能不同,所出现的进程更换频率不同。

我的运行结果为:

我随机截取的是两部分的图片,所以用上互斥量后就实现了三个线程交替把票全部卖完了。 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_47468969/article/details/123790118

智能推荐

怎样换通达信服务器文件夹,通达信的指标模版保存在那个文件夹,如何迁移-程序员宅基地

文章浏览阅读2.5k次。通达信的指标模版保存在那个文件夹,如何迁移在T0002文件夹里,PriCS.DAT是软件自带指标,PriGS.DAT是你的自定义指标。自选股票T0002\blocknew\ZXG.blk自编公式T0002\PriGS.DAT自编模板T0002\PriPack.DAT系统设置(常用指标)T0002\user.配置设置通达信\T0002\blocknew中ZXG.blk这个文件就是自选股文件,可以通过...

Intelli IDEA java调用DLL库_idea打开dll文件-程序员宅基地

文章浏览阅读6.8k次,点赞2次,收藏11次。Intelli IDEA创建java工程加载dll库_idea打开dll文件

时间序列预测基础教程系列(13)_归一化和标准化的区别与方法(Python)_对daily-minimum-temperatures中的数据进行处理-程序员宅基地

文章浏览阅读1.3w次,点赞10次,收藏51次。导读:数据的预处理方法有两种,分别是归一化和标准化什么时候用归一化?什么时候用标准化?  (1)如果对输出结果范围有要求,用归一化。  (2)如果数据较为稳定,不存在极端的最大最小值,用归一化。  (3)如果数据存在异常值和较多噪音,用标准化,可以间接通过中心化避免异常值和极端值的影响。正文:完成本教程后,您将了解:使用标准化的数据规范化和期望的局限性。 需要什么参数以..._对daily-minimum-temperatures中的数据进行处理

Scala日期操作、获取当前时间、获取前一天时间、获取两日期时间差、获取两日期间所有日期_scala获取dt.format前一天-程序员宅基地

文章浏览阅读7.2k次,点赞4次,收藏12次。获取当前时间var dateFormat: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd")var cal: Calendar = Calendar.getInstance()val nowday = dateFormat.format(cal.getTime())println(nowday)获取前1天日期val date = "2020-09-13"val myformat = new SimpleDateFormat("_scala获取dt.format前一天

ACM/ICPC WORLD FINAL 2015 A题_2015 icpcworld final-程序员宅基地

文章浏览阅读1k次。Fatima Cynara is an analyst at Amalgamated Artichokes (AA). As with any company, AA has had some very good times as well as some bad ones. Fatima does trending analysis of the stock prices for AA, and_2015 icpcworld final

【论文阅读】Deep Learning Workload Scheduling in GPU Datacenters:Taxonomy, Challenges and Vision-程序员宅基地

文章浏览阅读266次,点赞2次,收藏2次。论文阅读笔记Gao W, Hu Q, Ye Z, et al. Deep Learning Workload Scheduling in GPU Datacenters: Taxonomy, Challenges and Vision[J]. 讨论了数据中心负载作业的特征以及相关工作_deep learning workload scheduling in gpu datacenters: taxonomy, challenges a

随便推点

使用np.savetxt写入不覆盖原有内容,连续写入,循环写入_np.save函数会覆盖之前的吗-程序员宅基地

文章浏览阅读1.1w次,点赞11次,收藏28次。import numpy as npwith open('eye.txt','ab') as f: newresult1 = np.random.rand(2, 3) newresult2 = np.random.rand(2, 3) np.savetxt(f, newresult1, delimiter=" ") np.savetxt(f, newresult2, delimiter=" ") with open('eye.txt','ab') as f: ._np.save函数会覆盖之前的吗

HZAU 异或问题_异或问题博客-程序员宅基地

文章浏览阅读276次。1104: Sum and XORTime Limit: 5 Sec Memory Limit: 128 MBSubmit: 994 Solved: 56[Submit][Status][Web Board]Description Dr. Zeng is good at calculating sum of some numbers . Today , _异或问题博客

C++ vector中resize与reserve的比较_c++ 中的vector resize reserve 的区别-程序员宅基地

文章浏览阅读1.4w次,点赞3次,收藏5次。在介绍resize()与reserve()函数之前,可以先简单了解一下vector1、resize()既修改capacity大小,也修改size大小2、reserve()只修改capacity大小,不修改size大小_c++ 中的vector resize reserve 的区别

损失函数SSIM (structural similarity index) 的PyTorch实现_pytorch ssim-程序员宅基地

文章浏览阅读4w次,点赞33次,收藏182次。SSIM介绍结构相似性指数(structural similarity index,SSIM), 出自参考文献[1],用于度量两幅图像间的结构相似性。和被广泛采用的L2 loss不同,SSIM和人类的视觉系统(HVS)类似,对局部结构变化的感知敏感。SSIM分为三个部分:照明度、对比度、结构,分别如下公式所示:将上面三个式子汇总到一起就是SSIM:其中,上式各符号分..._pytorch ssim

小白学习HigherHRNet代码_higherhrnet代码分析-程序员宅基地

文章浏览阅读135次。每个节点都可以执行一部分训练工作,例如处理一部分的训练数据和更新模型的权重。这个函数的目标是将分布式训练的各个环节组织起来,从模型构建、数据加载、训练循环、学习率调整到模型保存,确保训练过程顺利进行。通道数是用来表示模型中不同层次的特征图(feature maps)的维度,它影响着模型的参数量、计算复杂度以及模型的性能。初始化分布式训练环境,包括分布式训练节点数量、分布式训练的进程与 GPU 分配等。根据训练效果,保存模型的检查点,包括当前状态和最好的状态。根据配置中的模型名称,调用相应的函数构建模型。_higherhrnet代码分析

实习日志(2)-程序员宅基地

文章浏览阅读675次,点赞2次,收藏3次。2021.07.12 星期一 新的星期开始,休息过两天之后,斗志满满。 今天先接触了递归,但由于之前学过,所以就一带而过了,在有些计算的时候需要考虑最优良的算法,这会使计算速度大大提升。接着又学习了词法环境,变量就是特殊内部对象的属性,与当前正在执行的代码块有关,操作变量实际上是操作该对象的属性。闭包就是指内部函数都可以访问其所在外部函数中被声明的变量和参数。这个应该是要记住,以后面试可能会被问到。还有函数自定义...

推荐文章

热门文章

相关标签