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(十):进程间通信IPC(四)之信号量

当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用:大于0,资源可以请求,将信号量的值-1(P操作); 等于0,无资源可用,进程会进入睡眠状态直至资源可用; 当进程不再使用...

Linux高级进程间通信:信号量

父进程产生三个子进程,每一个都使用p()和v()来阻止其他进程在同一时刻执行一段关键区域。  pv.h:/*semaphore exapmle header file */ #include #in...

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

转载自:http://blog.chinaunix.net/space.php?uid=13670711&do=blog&cuid=2034149 信号量(semaphore)简介当我们在多用户系统...

linux的进程间通信——信号量

信号量的本质是一种数据操作锁,它本⾝身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。信号量在此过程中负责数据操作的互斥、同步等功能。...

linux 信号量 机制 详解之一 进程间通信semget semop semctl

网上找了下,大都信号量都只是达到了相当于锁的机制,即都当作了二进制信号量在使用,没有找到进出队列,等待机制。所以当信号量达到n的时候的还需要大家自己深入理解了 首先我们要理清一个概念:l...

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

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

Linux进程间通信 -2信号量

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

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

使用消息队列即可实现消息的先进先出(FIFO), 但是使用共享内存实现消息的先进先出则更加快速;    我们首先完成C语言版本的shmfifo(基于过程调用), 然后在此基础上实现C++版本的S...
  • NK_test
  • NK_test
  • 2015年12月08日 14:25
  • 1913

Linux环境进程间通信 信号量

信号量与其他进程间通信方式不大相同,它主要提供对进程间共享资源访问控制机制。相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程也可以修改该标志。除了用于访问控制外,还可用于进程...

(转)Linux进程间通信——使用信号量

这篇文章将讲述别一种进程间通信的机制——信号量。注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物。有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号。下面...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux进程间通信之信号量
举报原因:
原因补充:

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