一起talk C栗子吧(第一百一十六回:C语言实例--线程同步之互斥量二)


各位看官们,大家好,上一回中咱们说的是线程同步之信号量的例子,这一回咱们继续说该例子。闲话休提,言归正转。让我们一起talk C栗子吧!

我们在上一回中详细介绍了互斥量相关函数的用法,这一回中,我们介绍如何使用这些函数来操作互斥量。

下面是详细的操作步骤:

  • 1.定义一个互斥量A,用来同步线程;
  • 2.在创建线程的进程中使用pthread_mutex_init函数初始化互斥量,互斥量的属性使用默认值;
  • 3.在读取数据的线程中读取数据,首先使用pthread_mutex_lock函数对互斥量A进行加锁操作;然后读取数据,最后使用pthread_mutex_unlock函数对互斥量A进行解锁操作;
  • 4.在第写数据的线程中修改数据,首先使用pthread_mutex_lock函数对互斥量A进行加锁操作;然后修改数据,最后使用pthread_mutex_unlock函数对互斥量A进行解锁操作;
  • 5.在创建线程的进程中使用pthread_mutex_destroy函数释放互斥量相关的资源;

看官们,正文中就不写代码了,详细的代码放到了我的资源中,大家可以点击这里下载使用。

我们写的代码是在信号量互斥代码的基础上修改而来的,不过我们在代码中使用互斥量代替了信号量。代码中了读/写数据的函数是自己实现的,目的是为了方便说明问题,在这两个函数中都使用了延时操作,目的是为了说明读或者写数据需要一定的时间。

在程序运行时可能会存在这样的情况:

  • 读操作还没有完成,就开始写操作,这样会造成读操作读取的数据不准确;
  • 写操作还没有完成,就开始读操作,这样会造成读操作读取的数据不准确;

下面是没有使用互斥量时程序的运行结果,请大家参考:

Create first thread         //创建第一个线程
Create second thread        //创建第二个线程
Thread ID::3076062016 -----------S---------- 
[Thread_1] start reading data     //第一个线程开始读取数据(对数据的第一个操作是读操作)
Thread ID::3067669312 -----------S---------- 
[Thread_2] start writing data     //第二个线程开始修改数据
[Thread_1] data = 0               //第一个线程读取到的是共享数据的初始值
[Thread_1] end reading data 
[Thread_2] data = 1               //第二个线程对共享数据进行修改
[Thread_2] end writing data 
[Thread_2] start writing data     
[Thread_1] start reading data     
[Thread_2] data = 2               
[Thread_2] end writing data 
[Thread_1] data = 2 
[Thread_1] end reading data 
[Thread_2] start writing data 
[Thread_2] data = 3 
[Thread_2] end writing data 
[Thread_1] start reading data 
[Thread_2] start writing data 
[Thread_1] data = 3 
[Thread_1] end reading data 
[Thread_2] data = 4 
[Thread_2] end writing data 
Thread ID::3067669312 -----------E----------   //第二个线程结束
[Thread_1] start reading data 
[Thread_1] data = 4 
[Thread_1] end reading data 
Thread ID::3076062016 -----------E----------  //第一个线程结束

从上面的结果中大家可以看到,第二个线程还没有写完数据,第一个线程就开始读取数据,而且读取到的是共享数据的初始化值。可见他读取到的值不是第二个线程修改后的数据,或者说不是准确的数据。再往下看,读取数据的线程和修改数据的线程交替运行,因此线程运行顺序也不正确。由此可见,如果不对线程进行同步操作,那么对共享数据进行操作会生成错误的结果。

下面是使用互斥量同步线程后程序的运行结果,请大家参考:

Create first thread                //创建第一个线程
Create second thread               //创建第二个线程
Thread ID::3075980096 -----------S----------   
[Thread_1] start reading data    //第一个线程开始读取数据(对数据的第一个操作是读操作)
Thread ID::3067587392 -----------S---------- 
[Thread_1] data = 0              //第一个线程读取到的是共享数据的初始值
[Thread_1] end reading data      //第一个线程读取共享数据结束
[Thread_2] start writing data    //第二个线程开始修改共享数据的值
[Thread_2] data = 1              //第二个线程修改了共享数据的值
[Thread_2] end writing data      //第二个线程修改共享数据结束
[Thread_1] start reading data    //第一个线程开始读取共享数据的值
[Thread_1] data = 1              //第一个线程读取到了正确的共享数据的值
[Thread_1] end reading data      //第一个线程读取共享数据结束
[Thread_2] start writing data 
[Thread_2] data = 2 
[Thread_2] end writing data 
[Thread_1] start reading data 
[Thread_1] data = 2 
[Thread_1] end reading data 
[Thread_2] start writing data 
[Thread_2] data = 3 
[Thread_2] end writing data 
[Thread_1] start reading data 
[Thread_1] data = 3 
[Thread_1] end reading data 
[Thread_2] start writing data 
[Thread_2] data = 4 
[Thread_2] end writing data 
Thread ID::3075980096 -----------E----------  //第一个线程结束
Thread ID::3067587392 -----------E----------  //第二个线程结束

从上面的结果中可以看到,第一个线程首先开始读取数据,读取完数据后第二个线程才开始修改数据;此时,第一个线程处于等待状态,直到第二个线程修改完数据后才开始读取数据,它读取到了准确的共享数据。再往下看,读取数据的线程和修改数据的线程依次有序地运行。由此可见,对线程进行同步操作后,对共享数据进行的操作顺序是正确的,从共享数据中读取到的值也是正确的。另外,再对比一下使用信号量对线程的同步操作。对共享数据的第一次操作是写操作,而使用互斥量同步线程时,对共享数据的第一次操作是读操作。正常来讲,肯定是先对数据进行修改,然后才能读数据中的内容。由此可见信号量对线程的运行顺序更加严格一些。

依据我们的经验来看,信号量经常用在计数或者对顺序有严格要求的情况中,而互斥量经常用访问共享资源的情况中。当然了,在同步线程的时候,大家可以依据自己的需要和程序的要求来选择信号量和互斥量。

各位看官,关于线程同步之互斥量的例子咱们就说到这里。欲知后面还有什么例子,且听下回分解 。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

talk_8

真诚赞赏,手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值