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


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

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

下面是详细的操作步骤:

  • 1.定义一个信号量A,用来同步线程;
  • 2.在创建线程的进程中使用sem_init函数把信号量A的值初始化为0;
  • 3.在读取数据的线程中使用sem_wait实现P操作;
  • 4.在第写数据的线程中修改数据,写数据的操作完成后使用sem_post实现V操作;
  • 5.在创建线程的进程中使用sem_destroy函数释放信号量相关的资源;

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

在代码中我们自己实现了读/写数据的函数,为了方便说明问题,在这两个函数中都使用了延时操作,目的是为了说明读或者写数据需要一定的时间

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

  • 读操作还没有完成,就开始写操作,这样会造成读操作读取的数据不准确;
  • 写操作还没有完成,就开始读操作,这样会造成读操作读取的数据不准确;
void read_data(char * str) 
{
    printf("[%s] start reading data \n",str);
    sleep(1);        //延时操作
    printf("[%s] data = %d \n",str,data); //对数据进行读操作,并且显示数据
    printf("[%s] end reading data \n",str);
}
void write_data(char * str)
{
    printf("[%s] start writing data \n",str);
    sleep(1);        //延时操作
    data++;          //对数据进程写操作
    printf("[%s] data = %d \n",str,data);
    printf("[%s] end writing data \n",str);
}

下面是程序的运行结果,请大家参考:

Create first thread          //创建第一个线程
Create second thread         //创建第二个线程
Thread ID::3076148032 -----------S---------- 
[Thread_1] start reading data      //第一个线程开始读取数据(对数据的第一个操作是读操作)
Thread ID::3067755328 -----------S---------- 
[Thread_2] start writing data      //第二个线程开始写数据
[Thread_1] data = 0                //写操作还没有完成,第一个线程读取到的数据是初始值
[Thread_1] end reading data 
[Thread_1] start reading data 
[Thread_2] data = 1         
[Thread_2] end writing data  //写操作完成,第二个线程通过写操作把数据修改为1
[Thread_1] data = 1          //写操作完成,第一个线程读取到的数据是写操作修改后的数据
[Thread_1] end reading data 
[Thread_1] start reading data 
[Thread_2] start writing data 
[Thread_1] data = 1 
[Thread_1] end reading data 
Thread ID::3076148032 -----------E----------  //读取数据的线程结束
[Thread_2] data = 2 
[Thread_2] end writing data 
[Thread_2] start writing data 
[Thread_2] data = 3 
[Thread_2] end writing data 
[Thread_2] start writing data 
[Thread_2] data = 4 
[Thread_2] end writing data 
Thread ID::3067755328 -----------E---------- //写数据的结束结束

大家从上面的结果中可以看到,对数据的读操作还没有完成,写操作就开始运行,或者是写操作还没有完成,读操作就开始运行。总之,读操作和写操作混合运行,程序中读操作显示的数据不准确。

我们按照上面对信号量的操作步骤,在程序中添加了信号量,通过信号量来实现线程同步。在代码中为了方便操作,只需要把宏定义代码前的注释去掉就可以:

//#define SEM_ENABLE 1

因为我们在代码中使用宏来控制信号量,详细如下:

#ifdef SEM_ENABLE
    res = sem_wait(&sem_value);
    if(res != 0)
    {
        printf(" sem wait failed \n");
    }
#endif
#ifdef SEM_ENABLE
        res = sem_post(&sem_value);
        if(res != 0)
        {
            printf(" sem post failed \n");
        }
#endif

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

Create first thread         //创建第一个线程
Create second thread        //创建第二个线程
Thread ID::3075992384 -----------S---------- 
Thread ID::3067599680 -----------S---------- 
[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::3075992384 -----------E----------  //读取数据的线程结束
Thread ID::3067599680 -----------E----------  //写数据的线程结束

从上面的运行结果中可以看到,在使用信号量对两个线程进行同步操作后,读取数据的线程和写数据的线程依次运行:先写数据,然后才读数据。这样保证了读取到的数据是准确的。

另外,大家可以看到,主进程先创建读取数据的线程,然后才创建写数据的线程。因此,应该是先读取数据,然后才写数据。不过,因为我们使用信号量对线程进行了同步,程序运行时,先执行写操作,然后才执行读操作。因此,在运行结果中,对数据的第一个操作是写操作。这一点可以和没有使用信号量的程序运行结果进行对比。

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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

talk_8

真诚赞赏,手有余香

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

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

打赏作者

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

抵扣说明:

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

余额充值