进程间通讯:信号量

来源:互联网 发布:淘宝商家从哪里进货 编辑:程序博客网 时间:2024/06/06 00:59

一、与信号量有关的几个知识点

 临界资源:同一时刻,只能被一个进程访问的资源 临界区:访问临界资源的代码区 原子操作:任何情况下都不能被打断的操作 内核对象:对通讯值的记录,类似管道

二、信号量的实质和作用

信号量的实质是记录资源同时能被多少个进程访问,作用于进程间的同步控制,不同于锁,它可以有N个有限值。
举个例子,信号量类似一个停车场,而锁类似停车场中的一个停车位,当车辆进入停车场时,停车位数量减一,但是在有其它空余停车位时,车辆依然可以进入停车场。而一个停车位有车辆时,其它车辆不可以进入这个停车位。
总的来说,信号量的通讯信息是资源的可访问数量,不同于管道的数据。

三、信号量的操作

1. 创建或获取:Int semget((key_t)key, int nsems, int flag);

Key是键值,是一个唯一的非零整数,类似于一个“身份证号”,其它进程通过这个“身份证号”来使用这组信号量;Nsems 用来确定内核创建的信号量数组大小;Flag 用来确定操作和权限,可以通过与上PC_CREAT在不存在该信号量时创建,存在时获取;返回值:非零的信号量标识符,其它函数根据信号量标识符来操作,而非键值;

栗子:int sem_id = semget( (key_t)1234, 1, 0666|IPC_CREAT );

2. P/V操作:int semop( int semid , struct sembuf * buf , int lenth);

Semid: semget返回的信号量标识符struct sembuf * buf:一个结构体    struct sembuf    {          Short sem_num;//除非使用一组信号量,否则它为0           short sem_op;//信号量在一次操作中需要改变的数据,通常是两个数,                        一个是-1,即P(等待)操作,//一个是+1,即V(发送信号)操作。          shortsem_flg;//通常为SEM_UNDO,使操作系统跟踪信号    };

3. 初始化和删除:int semctl(int sem_id, int sem_num, int command, uniousemun);

 Semid: semget返回的信号量标识符 sem_num:信号量数组的下标,如果只有一个元素,则为零command:操作,SETVAL为初始化,IPC_RMID为删除uniou semun:在初始化时,需要用到            unionsemun             {                int val; //初始化资源的个数               struct semid_ds *buf;                unsigned short *arry;             }; 

四、通过一个简单实例来掌握信号量,进程A负责读取键盘输入,直到读取“OK”,进程B打印出100以内的素数。

需要注意的是,在多个进程之间使用信号量通讯,可以将P操作之后的代码认为是临界区,即P操作不是简单的减一,而是要理解为:

如果能做P操作之后临界区的事件,那么减一,否则等待

sem.h 为头文件
sem.c 将信号量操作进行了简单的封装
maina.c和mainb.c是一个简单的示例:
maina读取键盘输入,直到输入OK,mainb打印100以内的素数

sem.h:

#ifndef _SEM_H#define _SEM_H#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <assert.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semid;union semun{    int val;    //struct semid_ds *buf;    //unsigned short * arry;};void sem_get(int key,int len,int val);void sem_p();void sem_v();void sem_del();#endif

sem.c:

#include "sem.h"void sem_get(int key,int len,int val){    semid = semget((key_t)key,len,0666);    if(semid == -1)    {        semid = semget((key_t)key,len,0666|IPC_CREAT);        assert(semid != -1);        union semun v;        v.val = val;        if(semctl(semid,0,SETVAL,v)==-1)        {            perror("error");            exit(0);        }    }}void sem_p(){    struct sembuf sem;    sem.sem_num = 0;    sem.sem_op = -1;    sem.sem_flg = SEM_UNDO;    if(semop(semid, &sem, 1)==-1)    {        perror("perror");        exit(0);    }}void sem_v(){    struct sembuf sem;    sem.sem_num = 0;    sem.sem_op = 1;    sem.sem_flg = SEM_UNDO;    if(semop(semid, &sem, 1)==-1)    {        perror("perror");        exit(0);    }}void sem_del(){    if(semctl(semid,0,IPC_RMID)==-1)    {        perror("delperror");        exit(0);    }}

进程A:

#include "sem.h"int main(){    sem_get(111,1,0);    while(1)    {        char buff[128]={0};        fgets(buff,127,stdin);        if(strncmp(buff,"ok",2)==0)        {            sem_v();            break;        }    }    sem_del();    return 0;}

进程B:

#include "sem.h"void prime(){    int i,j;    for(i=2;i<=100;i++)    {        for(j=2;j<=i-1;j++)        {            if(i%j==0)                break;        }        if(j>=i)          printf("%d\n",i);    }}int main(){    sem_get(111,1,0);    sem_p();    prime();    return 0;}
原创粉丝点击