使用信号量控制Linux线程同步

线程同步

在现实生活中,有些东西就必须是按顺序执行的,只有我完成了以后,你才能在我的劳动成果上接着干;不能我还没有完成,你就开始干活了。这就是线程同步最直白的解释了。

在进行程序设计时,亦是如此。线程同步,同步的是什么?它同步的是对共享资源(内存区域,公共变量等)或者临界区域的访问。有的时候,这些共享 资源和临界区域,就只能容忍一个线程对它进行操作(读或者写,读操作一般不控制,主要是写操作),这个时候,我们必须要对这些共享资源或者临界区域进行同 步,那么如何对它们进行线程同步呢?

在Linux中主要提供了以下两种方法:

  • 用信号量进行同步
  • 用互斥量进行同步

不管用什么方法,都是为了线程同步,而这篇文章就对信号量进行线程同步进行详细的总结。

什么是信号量

首先来搞清楚信号量的概念。信号量是一个特殊类型的变量,它可以被增加或减少,但对它的访问都会被保证是原子操作,即使在一个多线程程序中也是 如此。也就是说,如果一个程序中有两个或多个线程试图改变一个信号量的值,系统将保证所有的操作都将依次进行。如果换成普通的变量,来自同一个程序中的不 同线程的冲突操作将会导致不确定的操作。

在工作中,你会遇到两种信号量:二进制信号量和计数信号量。二进制信号量只有0和1两种取值,而计数信号量则有更大的取值范围。如果某个共享资源只能被一个线程访问,那么二进制信号量则是最好的打算;如果有多个线程需要访问共享资源呢,使用计数信号量则是个好的主意。

信号量相关API

在Linux中已经提供了一些相关的API接口来实现信号量,先来和这些接口混一个脸熟,之后再通过一个小例子来熟悉如何使用这些接口。

sem_wait会对信号量的值进行减1操作,但是它会等到信号量的值大于等于1时,才开始进行减1的操作。所以,如果对值为2的信号量调用 sem_wait,线程会继续执行;而如果对为0的信号量进行sem_wait操作,这个函数就会等待,直到有其它线程增加了该信号量的值使其不再为0为 止。

一个小实例

关于信号量操作的API函数都已经介绍完了,现在就通过一个小的程序来用一用这些函数,通过实际的编码,能更好的掌握如何使用这些函数。

接下来代码要完成这样一个功能:

  • 主线程从标准输入终端读取输入的内容;
  • 子线程1将主线程中输入的内容转换成大写。

来吧,我们就按照上面的功能来编码实现一下。功能简单,我准备这样实现:

  • 在主线程初始化信号量为0;
  • 当主线程输入完成以后,调用sem_post增加信号量的值;
  • 在子线程1中,调用sem_wait,等到信号量的值为1时,就减少信号量的值,然后执行线程中的代码。

好了,编码吧。

好不容易编码完成了,测试一下,效果还是不错的。有小伙伴说了,转小写转大写,直接用 toupper 不就得了么,也是这么个道理。代码就这样了,运行起来,效果还不错,也还能得到之前预期的效果。但是,但是……,多线程程序,永远都是那么多的坑,即使我就写了这么几行代码,我还是嗅到了坏味道。

我先这么分析一下,如果线程1运行到了以下这行代码:

这个时候,我接着在终端中输入内容,这个时候, work_area 保存的内容是否就会变了呢?不妨做个试验,我们把代码修改成这样:

再运行程序,测试一下。你在终端输入快点,然后就发现,输出就变了。不知道我这么说,看官能否明白。简单的说,就是我的线程1还没有将所有字符转换为大写,主线程又开始了输入新的内容,这个时候, work_area 的内容就发生了紊乱,得到的内容并不是我们期望的,同时,信号量的值也会发生错乱。

为什么没有加 sleep(1) 的时候,就没有出现这样的问题呢?我只能说,机器运行的速度快过你认为的速度,加上了 sleep(1) 就相当于认为的给机器降降速。

好了,问题出来了,如何解决呢?

改进版

问题出来了,我们就需要去想办法解决这个问题,由于线程1还没有完成变换,主线程又开始了新的输入。所以,主线程必须要等到线程1完成以后才能 进行新的输入,那么,我们就需要再加入一个信号量,当线程1完成转换时,增加该信号量;主线程完成输入以后,减少该信号量。再来试一试:

这样处理完成以后,所有的输入都会依次进行处理,就不会出现紊乱的问题。所以,对于多线程编程中的这些坑,你是否也踩过呢?希望大家也能和我分享你踩过的坑,共同学习,共同进步。

总结

本来是不想总结的,后来一想,还是挺重要的东西,还是写出来,总结一下吧,再加深一遍记忆。

有人说了,这种Linux线程同步的文章,网上大把,你再写一篇,岂不是多此一举呢?我想说的是,我博客中的文章,每一篇网上都有大把,网上的 是别人总结的,那不是你的;别人总结出来,那是他们经过思考以后才写出来的东西。我博客中的文章是我经过思考写出来的东西,如果你觉的网上有了,就去放弃 自己的总结,那么就相当于放弃了自己的思考。我写文章,一来是自己思考的结晶;二来是为了和大家分享,一起探讨相关知识点。文章,只有自己认真思考过了, 才发现它真的不好写,不要相信你转载以后,那篇文章就是你的了。

2015年,新年新起点。希望大家也能总结出自己的文章。多打开电脑,多打开vim,多敲敲键盘(coding…)。

2015年1月5日 于深圳。

时间: 2024-11-10 01:11:50

使用信号量控制Linux线程同步的相关文章

Linux线程同步---信号量

首先讲一下线程同步信号量的几个关键步骤! 1.定义并初始化信号量. (1) sem_t bin_sem; (2)  res = sem_init(&bin_sem,0,0); 详细步骤可以查看man帮助页面 2.使用信号量 (1) 信号量加1操作.sem_post(&bin_sem); (2) 信号量等待并减1操作.sem_wait(&bin_sem); 初始化后一般处于等待状态,执行某个操作后加1,而另个一个操作执行前进行等待操作.如果有多个线程,通常是一个线程进行加1操作,另外

Linux 线程同步的三种方法(互斥锁、条件变量、信号量)

互斥锁 1 #include <cstdio> 2 3 #include <cstdlib> 4 5 #include <unistd.h> 6 7 #include <pthread.h> 8 9 #include "iostream" 10 11 using namespace std; 12 13 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 14 15 int tmp; 16

【转】 Linux 线程同步的三种方法

线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点.linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量. 一.互斥锁(mutex) 通过锁机制实现线程间的同步. 初始化锁.在Linux下,线程的互斥量数据类型是pthread_mutex_t.在使用前,要对它进行初始化.静态分配:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;动态分配:int pthread_mutex_init(pthread_m

linux线程同步(队列方式)

看了一些关于信号量的线程同步方式,今天用了一下. 我对于线程同步一直有疑问,在主线程和子线程处理时间不相同的时候,用这种信号量,如何保证同步. 假如主线程比较快,信号量连加了n个,但是子线程就不断减这个n,减到0.但是如果主线程太快太快,需要停一停,比如缓冲区快溢出了,主线程需要挂起. 由什么来唤醒主线程呢?子线程?不过这样的话,容易造成主线程死锁,或者主和子都卡死. 下面的程序,没有用到信号量同步,信号量只是负责开启子线程而已.主要是队列的实现而已.等我把上面的问题解决完会写上更新的程序. 队

Linux线程同步

线程同步-互斥锁 1.初始化互斥锁pthread_mutex_init() int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); 例: pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); 2.锁住互斥锁pthread_mutex_lock() int pthread_mutex_lock(pt

LINUX线程同步初探

0x00.什么是线程同步 同步,又称直接制约关系,是指多个线程(或进程)为了合作完成任务,必须严格按照规定的 某种先后次序来运行 0x01.案例代码 1 void* PthreadFunc(void* argc); 2 int flag_num = 1; 3 4 int main(int argc, char* argv[]) 5 { 6 pthread_t pid; 7 void* ret_val; 8 9 int create_status = pthread_create(&pid, NU

linux线程同步实例

[Linux多线程]三个经典同步问题 - 神奕的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/lisonglisonglisong/article/details/45390227 Linux多进程多线程互斥同步例子_Linux编程_Linux公社-Linux系统门户网站 http://www.linuxidc.com/Linux/2013-01/78394.htm UNIX/Linux-线程控制(实例入门篇) - 菜鸟的自留地- 博客频道 - CSDN.N

linux 线程同步(二)

信号量 信号量是互斥锁的升级版把互斥锁中1变成了n,举个简单的例子:假设现在有10个人,有一部手机,这10个人都竞争来使用手机打电话这就是互斥锁.对于信号量,现在可能是有4部手机,这10个人都竞争来使用手机打电话.相比互斥锁信号量由1变成了4.信号量相也就是操作系统中pv操作,它广泛应用进程或者线程间的同步与互斥. 相关库函数介绍 #include <semaphore.h>//所需头文件 //初始化信号量sem初始化的时候可以指定信号量的初始值,以及是否可以在多进程间共享value表示要信号

Linux线程同步------屏障

屏障是Linux中协调多个线程并行工作的同步机制,屏障允许每个线程等待直到所有的合作线程到达某一点,然后继续从该点执行,pthread_join是一种屏障但只允许一个线程等待,pthread_barrier允许任意数量的线程等待! pthread_barrier_init(pthread_barrier_t *屏障,属性,unsigned int 屏障计数值): pthread_barrier_wait(pthread_barrier_t *屏障):在每个线程中调用则计数值加一并将当前线程阻塞在