linux进程间通信之信号量

原创 2016年08月29日 21:52:54

1 信号量

信号量与管道和信号不同,它是一个计数器,用于多进程对共享数据对象的访问,通常与共享内存相结合使用。一般在多任务环境系统下,多个进程会同时运行,特别是在多核cpu的情况下,并且有些进程相互之间可能存在一定关联。多个进程可能为了完成同一个任务相互协作,这样形成进程之间的同步关系。而且在不同进程之间,为了争夺有限的系统资源(硬件或软件资源)会进入竞争状态,这就是进程之间的互斥关系。
进程间的互斥和同步关系存在根源在与临界资源。临界资源是在同一个时刻只允许有限个(通常只有一个)进程可以访问或修改资源。通常包括硬件资源(处理器,内存,存储器以及其他处于外围设备)和软件资源(共享代码,共享结构和变量等)。访问临界资源的代码叫做临界区,临界区本身也会成为临界资源
信号量可以用来解决进程之间的同步与互斥问题。通常为了获得共享资源,进行需要执行下列操作:
1:建立初始化控制该资源的信号量(semget(), semctl()函数)
2:若信号量的值为正,则进程可以使用该资源,进程将信号量值减为1,通常称为P操作
3:若信号量的值为0,则进程进入休眠状态,直到值大于零
4:若使用完该资源后,则释放该资源,将信号量值加1,通常称为V操作。

使用信号量临界区的伪代码可以表示为:

INIT_VAL(s) /*初始化信号量*、
非临界区
P(S) /*P操作 -1*/
临界区
V(S) /*V操作 +1*/
非临界区

通常使用信号量只取0和1, 被称为二维信号量。

2: 信号量主要函数

新建或获取信号量函数:
int semget(key_t key, int nsems, int flag)
参数:
Key:信号量的键值,多个进程可以通过它访问同一个信号量,其中有个特殊值IPC_PRIVATE。用于创建当前进程的 私有信号量
nsems: 创建信号量数目,通常为1.
semflag:同open()函数的权限位,也可以用八进制表示法,其中使用IPC_CREATE标志创建新的信号量,即使该信号量已经存在,也不会出错。如果同时使用IPC_EXECL标志可以创建唯一一个新 的信号量,此时如果该信号量已经存在,该函数会返回出错。

信号量操作函数:
int semctl(int semid, int senum, int cmd, union semun arg)
参数:
semid: semget()函数返回的信号量标识符
semnum, 信号量编号,当使用信号量集时才会被用到。通常取值为0,就是使用单个信号量
cmd: 对信号量的各种操作,通常使用一下几种:
IPC_STAT:获得该信号量的semid_ds结构,并存放在由第4个参数arg的buf指向的semid_ds结构中。semid_ds是在系统中描述信号量的数据结构
IPC_SETVL:将信号量值设置为arg的val值
IPC_GETVAL:返回信号量的当前值
IPC_RMID:从系统中,删除信号量(或者信号量集)
arg:是unio semnn结构
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
}

实现PV操作重要函数semop:
int semop(int semid, struct sembuf *sops, size_t nsops)
参数:
semid: semget()函数返回的信号量标识符。
sops:指向信号量操作数组,
struct sembuf
{
short sem_num; /* 信号量编号,使用单个信号量时,通常取值为 0 */
short sem_op;
/* 信号量操作:取值为-1 则表示 P 操作,取值为+1 则表示 V 操作*/
short sem_flg;
/* 通常设置为 SEM_UNDO。这样在进程没释放信号量而退出时,系统自动
释放该进程中未释放的信号量 */
}

3:实验用例

下面用一个例子来现实信号量对进程间同步的操作,参考《linux应用程序开发标准教程》中:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};


int init_sem(int sem_id, int init_value)
{
    union semun sem_union;

    sem_union.val = init_value;
    if(semctl(sem_id, 0, SETVAL, sem_union) == -1)
    {
        perror("Initialize semaphore");
        return -1;
    }

    return 0;
}

int del_sem(int sem_id)
{
    union semun sem_union;

    if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
    {
        perror("Delete semaphore");
        return -1;
    }

}


int sem_p(int sem_id)
{
    struct sembuf sem_b;

    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;

    if (semop(sem_id, &sem_b, 1) == -1)
    {
        perror("P operation fail");
        return -1;
    }

    return 0;
    }

int sem_v(int sem_id)
{
    struct sembuf sem_b;

    sem_b.sem_num = 0;
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;

    if (semop(sem_id, &sem_b, 1) == -1)
    {
        perror("V operation");
        return -1;
    }

    return 0;
}

int main(void)
{
    pid_t result;
    int sem_id;
   /* create sem*/
    sem_id = semget(ftok(".", 'a'), 1, 0666|IPC_CREAT);

    /* init sem */
    init_sem(sem_id, 0);

    result = fork();
    if (result == -1)
    {
        perror("Fork\n");
    }
    else if(result == 0)
    {
        printf("Child process will wait for some seconds... \n");
        sleep(3);
        printf("The returned value is %d in the child process(PID = %d)\n", result, getpid());
        sem_v(sem_id);
    } else
    {
        sem_p(sem_id);
        printf("The return value is %d in the father process(PID = %d)\n", result, getpid());
        sem_v(sem_id);
    }
    exit(0);
}

运行结果:
root@baohua-VirtualBox:/repo/training/fork# ./a.out
Child process will wait for some seconds…
The returned value is 0 in the child process(PID = 4203)
The return value is 4203 in the father process(PID = 4202)

以上实验代码github地址:https://github.com/zhikunhuo/training.git

Linux进程间通信——使用信号量

这篇文章将讲述别一种进程间通信的机制——信号量。注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物。下面就进入信号量的讲解。 一、什么是信号量 为了防止出现因多个程序同时访问一个...
  • ljianhui
  • ljianhui
  • 2013年08月24日 00:12
  • 117868

进程间通信——信号量、互斥锁等的异同

进程间通信——信号量、互斥锁等的异同 最早接触在系统上编程,是在嵌入式Linux上完成几项功能。当时就是按照写单片机程序的思维写的。实现几个功能,就用了一个进程,单线程来做。 后来...
  • tietao
  • tietao
  • 2014年01月14日 23:39
  • 8541

笔记:进程间通信——同步(互斥锁、读写锁、条件变量、信号量)以及Linux中的RCU

1.互斥锁 多个线程的IPC,需要同步,同步有隐式的和显示的: 比如unix提供的管道和FIFO,由内核负责同步,比如read发生在write之前,那么read就会被内核阻塞,这中同步是由内核负责的,...
  • yyf_it
  • yyf_it
  • 2016年06月20日 20:17
  • 1123

Linux进程间通信——使用信号量

这篇文章将讲述别一种进程间通信的机制——信号量。注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物。 一、什么是信号量 为了防止出现因多个程序同时访问一个共享...
  • midion9
  • midion9
  • 2015年11月16日 10:20
  • 250

linux进程间通信之信号量(semaphore)

转载自:http://blog.chinaunix.net/space.php?uid=13670711&do=blog&cuid=2034149 信号量(semaphore)简介当我们在多用户系统...
  • Sandeldeng
  • Sandeldeng
  • 2016年10月17日 11:05
  • 225

Linux进程间通信(IPC)编程实践(十)System V信号量---PV操作经典题目

[cpp] view plaincopy //P原语       //P(semaphore *S)       wait(semaphore *S)       ...
  • NK_test
  • NK_test
  • 2015年12月06日 20:44
  • 2367

Linux进程间通信——信号量

信号量:是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该...
  • qq_35420908
  • qq_35420908
  • 2017年03月10日 22:44
  • 520

Linux进程间通信-信号量

一、什么是信号量 首先信号量的本质是一种数据操作锁,它本身不具备数据交互的能力,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信的,它本身是一种标识,主要在过程中负责数据操作的互斥、同步...
  • qq_36528114
  • qq_36528114
  • 2017年06月08日 16:49
  • 156

Linux进程间通信 -2信号量

最初有TA&T System V.2 UNIX系统引入,被称为System V IPC。 信号量 : 用于管理对资源的访问。 内存共享: 用于程序之间高效地共享数据。 消息队列: 在程序之间传递数据的...
  • mandagod
  • mandagod
  • 2016年10月24日 19:52
  • 335

Linux进程间通信(IPC)编程实践(十一)System V信号量---实现一个先进先出的共享内存shmfifo

使用消息队列即可实现消息的先进先出(FIFO), 但是使用共享内存实现消息的先进先出则更加快速;    我们首先完成C语言版本的shmfifo(基于过程调用), 然后在此基础上实现C++版本的S...
  • NK_test
  • NK_test
  • 2015年12月08日 14:25
  • 2025
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux进程间通信之信号量
举报原因:
原因补充:

(最多只允许输入30个字)