`
xitong
  • 浏览: 6177618 次
文章分类
社区版块
存档分类
最新评论

linux 多线程编程 ---- 信号量的使用

 
阅读更多

信号是E.W.Dijkstra在二十世纪六十年代末设计的一种编程架构。Dijkstra的模型与铁路操作有关:假设某段铁路是单线的,因此一次只允许一列火车通过。信号将用于同步通过该轨道的火车。火车在进入单一轨道之前必须等待信号灯变为允许通行的状态。火车进入轨道后,会改变信号状态,防止其他火车进入该轨道。火车离开这段轨道时,必须再次更改信号的状态,以便允许其他火车进入轨道。在计算机版本中,信号以简单整数来表示。线程等待获得许可以便继续运行,然后发出信号,表示该线程已经通过针对信号执行P操作来继续运行。线程必须等到信号的值为正,然后才能通过将信号值减1来更改该值。完成此操作后,线程会执行V操作,即通过将信号值加1来更改该值。这些操作必须以原子方式执行,不能再将其划分成子操作,即,在这些子操作之间不能对信号执行其他操作。在P操作中,信号值在减小之前必须为正,从而确保生成的信号值不为负,并且比该值减小之前小1。在P和V操作中,必须在没有干扰的情况下进行运算。如果针对同一信号同时执行两个V操作,则实际结果是信号的新值比原来大2。对于大多数人来说,如同记住Dijkstra是荷兰人一样,记住P和V本身的含义并不重要。但是,真正学术的角度来说,P代表prolagen,这是由proberen te verlagen演变而来的杜撰词,其意思是尝试减小。V代表verhogen,其意思是增加。Dijkstra的技术说明EWD74中介绍了这些含义。sem_wait(3RT)和sem_post(3RT)分别与Dijkstra的P和V操作相对应。sem_trywait(3RT)是P操作的一种条件形式。如果调用线程不等待就不能减小信号的值,则该调用会立即返回一个非零值。有两种基本信号:二进制信号和计数信号量。二进制信号的值只能是0或1,计数信号量可
以是任意非负值。二进制信号在逻辑上相当于一个互斥锁。

不过,尽管不会强制,但互斥锁应当仅由持有该锁的线程来解除锁定。因为不存在“持有信号的线程”这一概念,所以,任何线程都可以执行V或sem_post(3RT)操作。计数信号量与互斥锁一起使用时的功能几乎与条件变量一样强大。在许多情况下,使用计数信号量实现的代码比使用条件变量实现的代码更为简单。但是,将互斥锁用于条件变量时,会存在一个隐含的括号。该括号可以清楚表明程序受保护的部分。对于信号则不必如此,可以使用并发编程当中的go to对其进行调用。信号的功能强大,但是容易以非结构化的不确定方式使用。

1 命名信号量和未命名信号量

POSIX信号可以是未命名的,也可以是命名的。未命名信号在进程内存中分配,并会进行初始化。未命名信号可能可供多个进程使用,具体取决于信号的分配和初始化的方式。未命名信号可以是通过fork()继承的专用信号,也可以通过用来分配和映射这些信号的常规文件的访问保护功能对其进行保护。命名信号类似于进程共享的信号,区别在于命名信号是使用路径名而非pshared值引用的。命名信号可以由多个进程共享。命名信号具有属主用户ID、组ID和保护模式。对于open、retrieve、close和remove命名信号,可以使用以下函数:sem_open、sem_getvalue、sem_close和sem_unlink。通过使用sem_open,可以创建一个命名信号,其名称是在文件系统的名称空间中定义的。

2 计数信号量概述

从概念上来说,信号量是一个非负整数计数。信号量通常用来协调对资源的访问,其中信号计数会初始化为可用资源的数目。然后,线程在资源增加时会增加计数,在删除资源时会减小计数,这些操作都以原子方式执行。如果信号计数变为零,则表明已无可用资源。计数为零时,尝试减小信号的线程会被阻塞,直到计数大于零为止。

由于信号无需由同一个线程来获取和释放,因此信号可用于异步事件通知,如用于信号处理程序中。同时,由于信号包含状态,因此可以异步方式使用,而不用象条件变量那样要求获取互斥锁。但是,信号的效率不如互斥锁高。缺省情况下,如果有多个线程正在等待信号,则解除阻塞的顺序是不确定的。信号在使用前必须先初始化,但是信号没有属性。

3 初始化信号量

使用sem_init(3RT)可以将sem所指示的未命名信号变量初始化为value。
sem_init语法
int sem_init(sem_t *sem, int pshared, unsigned int value);
#include <semaphore.h>
sem_t sem;
int pshared;
int ret;
int value;
/* initialize a private semaphore */
pshared =0;
value =1;
ret = sem_init(&sem, pshared, value);
如果pshared的值为零,则不能在进程之间共享信号。如果pshared的值不为零,则可以在进程之间共享信号。

注意:

(1)多个线程决不能初始化同一个信号。
(2)不得对其他线程正在使用的信号重新初始化。

4 初始化进程内信号量

pshared为0时,信号只能由该进程内的所有线程使用。
#include <semaphore.h>
sem_t sem;
int ret;
int count = 4;
/* to be used within this process only */
ret = sem_init(&sem, 0, count);

5 初始化进程间信号量

pshared不为零时,信号可以由其他进程共享。
#include <semaphore.h>
sem_t sem;
int ret;
int count = 4;
/* to be shared among processes */
ret = sem_init(&sem, 1, count);

6 sem_init返回值

sem_init()在成功完成之后会返回零。其他任何返回值都表示出现了错误。如果出现以下任一情况,该函数将失败并返回对应的值。

EINVAL
描述:参数值超过了SEM_VALUE_MAX。
ENOSPC
描述:初始化信号所需的资源已经用完。到达信号的SEM_NSEMS_MAX限制。
ENOSYS
描述:系统不支持sem_init()函数。
EPERM
描述:进程缺少初始化信号所需的适当权限。

7 增加信号

sem_post语法
int sem_post(sem_t *sem);
#include <semaphore.h>
sem_t sem;
int ret;
ret = sem_post(&sem); /* semaphore is posted */
如果所有线程均基于信号阻塞,则会对其中一个线程解除阻塞。

sem_post返回值
sem_post()在成功完成之后会返回零。其他任何返回值都表示出现了错误。如果出现以下情况,该函数将失败并返回对应的值。
EINVAL
描述: sem所指示的地址非法。

8 基于信号计数进行阻塞

使用sem_wait(3RT)可以阻塞调用线程,直到sem所指示的信号计数大于零为止,之后以原
子方式减小计数。
sem_wait语法
int sem_wait(sem_t *sem);
#include <semaphore.h>
sem_t sem;
int ret;
ret = sem_wait(&sem); /* wait for semaphore */
sem_wait返回值
sem_wait()在成功完成之后会返回零。其他任何返回值都表示出现了错误。如果出现以下任一情况,该函数将失败并返回对应的值。

EINVAL
描述: sem所指示的地址非法。
EINTR
描述:此函数已被信号中断。

9 减小信号计数

使用sem_trywait(3RT)可以在计数大于零时,尝试以原子方式减小sem所指示的信号计数。
sem_trywait语法
int sem_trywait(sem_t *sem);
#include <semaphore.h>
sem_t sem;

int ret;
ret = sem_trywait(&sem); /* try to wait for semaphore*/
此函数是sem_wait()的非阻塞版本。sem_trywait()在失败时会立即返回。
sem_trywait返回值
sem_trywait()在成功完成之后会返回零。其他任何返回值都表示出现了错误。如果出现以下任一情况,该函数将失败并返回对应的值。
EINVAL
描述: sem所指示的地址非法。
EINTR
描述:此函数已被信号中断。
EAGAIN
描述:信号已为锁定状态,因此该信号不能通过sem_trywait()操作立即锁定。

10 销毁信号状态

使用sem_destroy(3RT)可以销毁与sem所指示的未命名信号相关联的任何状态。
sem_destroy语法
int sem_destroy(sem_t *sem);
#include <semaphore.h>
sem_t sem;
int ret;
ret = sem_destroy(&sem); /* the semaphore is destroyed */

sem_destroy返回值
sem_destroy()在成功完成之后会返回零。其他任何返回值都表示出现了错误。如果出现以
下情况,该函数将失败并返回对应的值。
EINVAL
描述: sem所指示的地址非法。

分享到:
评论

相关推荐

    linux多线程编程

    linux多线程编程 声明:本文是网上整理的资料,版权属其作者本人所有。 1 第一章 线程基础知识 2 一.什么是线程 2 二.线程的优点 2 三.线程的缺点 2 四.线程的结构 2 五.线程标识 2 六.线程的创建 3 七..线程...

    实验二、嵌入式Linux多线程编程实验

    2. 掌握如何利用信号量完成线程间的同步与互斥。 3. 熟悉Makefile工作原理,掌握编写Makefile的编写方法。 二、实验基本要求 1. 掌握熟悉线程的定义及操作方法。 2. 利用信号量的PV操作完成完成以下单个生产者和单个...

    linux多线程编程.ppt

    1、Linux下线程概述 2、linux线程实现 。。。。。。。。。 2.4 信号量线程控制 等等 基本概述了linux下多线程编程的一些基本内容 入门教程 28页

    多线程编程原理与实战(超优秀)

    包含详细介绍多线程编程的四个文档及可运行的代码: 1、多线程编程-API.doc 2、多线程编程-互斥锁.doc 3、多线程编程-信号量.doc 4、多线程编程-监控线程.doc 其中监控线程部分有较好的参考价值。

    linux_code.rar_linux 多线程_linux 线程_多线程编程

    linux 系统的编程的源码,对初学者很有帮助。多线程、内存、信号量等程序。

    Linux c++多线程串口编程demo

    使用多线程进行串口编程,获取串口数据,利用互斥锁和信号量在不同的线程中安全地操作数据,希望该demo能帮助你快速理解并掌握上述知识。

    基于linux的多线程编程

    在linux下实现了通过互斥信号量实现同步,这个实验模拟了生产者消费者问题

    linux网络编程-宋敬彬-part3

    4.4.1 多线程编程实例 127 4.4.2 Linux下线程创建函数pthread_create() 129 4.4.3 线程的结束函数pthread_join()和pthread_exit() 129 4.4.4 线程的属性 130 4.4.5 线程间的互斥 132 4.4.6 线程中使用信号...

    linux网络编程-宋敬彬-part2

    4.4.1 多线程编程实例 127 4.4.2 Linux下线程创建函数pthread_create() 129 4.4.3 线程的结束函数pthread_join()和pthread_exit() 129 4.4.4 线程的属性 130 4.4.5 线程间的互斥 132 4.4.6 线程中使用信号...

    linux多线程编程详解教程(线程通过信号量实现通信代码)

    主要介绍了linux多线程编程详解教程,提供线程通过信号量实现通信的代码,大家参考使用吧

    Linux c语言多线程实现生产者/消费者问题

    以生产者/消费者问题为例来阐述Linux线程的控制和通信。一组生产者线程与一组消费者线程通过缓冲区发生联系。生产者线程将生产的产品送入缓冲区,消费者线程则从中取出产品。缓冲区有N 个,是一个环形的缓冲池。 ...

    第3章_linux多线程编程

    Linux多线程编程 1、多线程模型在单处理器模型和多处理器系统上,都能改善响应时间和吞吐量。 2、线程包含了表示进程内执行环境必须的信息,包括线程ID、一组寄存器、栈、调度优先级、策略、信号屏蔽字、errno变量、...

    关于Linux多线程编程

    Linux下的pthread全面介绍 包括条件变量与信号量

    linux网络编程-宋敬彬-part1

    4.4.1 多线程编程实例 127 4.4.2 Linux下线程创建函数pthread_create() 129 4.4.3 线程的结束函数pthread_join()和pthread_exit() 129 4.4.4 线程的属性 130 4.4.5 线程间的互斥 132 4.4.6 线程中使用信号...

    mutexes-variables-semaphores.rar_linux 线程锁_mutexes_锁和信号量

    Linux多线程编程中互斥锁、条件变量和信号量

    实验二、嵌入式Linux多线程编程实

    2. 掌握如何利用信号量完成线程间的同步与互斥。 3. 熟悉Makefile工作原理,掌握编写Makefile的编写方法。 二、实验基本要求 1. 掌握熟悉线程的定义及操作方法。 2. 利用信号量的PV操作完成完成以下单个生产者和单个...

    linux多线程编程(五)

    线程  线程是计算机中独立运行的... 使用多线程的理由之一是和进程相比,它是一种非常“节俭”的多任务操作方式。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它

    Linux下基于socket多线程并发通信的实现

    Linux下基于socket多线程并发通信的实现,论文,pdf文档

    Linux多线程服务端编程:使用muduo C++网络库

    《Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。...

    详解Linux多线程使用信号量同步

    本篇文章主要是介绍了Linux多线程使用信号量同步,详细讲诉了信号量的接口和使用,有需要的朋友可以了解一下。

Global site tag (gtag.js) - Google Analytics