进程间通信之信号量

信号量的本质是一种数据操控锁,它本身不具有数据交换的功能,而是通过来控制其他的通信资源来实现进程间通信的,信号主要负责数据的同步与互斥功能。

进程请求一个使用信号量来表示的资源时,首先要读取信号量的值来判断资源是否能被使用,若信号量的值大于0,资源可用,等于0,无资源可用,同时进程会进入睡眠状态,直到有资源可用。

当进程不再使用一个信号量控制的共享资源时,信号量的值+1,对信号量的值进行的增减操作均为原子操作,这是由于信号量主要的作用是维护资源的互斥或多进程的同步访问。而在信号量的创建及初始化上,不能保证操作均为原子性。

信号量是为了解决多个进程同时访问一块资源所产生的问题的方法,他办证一个时间只有一个进程访问这块资源,按序访问。

信号量的工作原理:
由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.
举个例子,就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,因为当它试图执行
P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。
代码实现成对打印AABB
comm.h

#ifndef _COMM_H_
#define _COMM_H_
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define PATHNAME "."
#define PROJ_ID 0x6666
#endif
union semun 
{
    int   val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO                                                                                                                                    (Linux-specific) */
};
int creatSemSet(int num);
int initSemSet(int semid,int num,int val);
int getSemSet(int num);
int destorySemSet(int semid);
int P(int semid,int num);
int V(int semid,int num);
static int comPV(int semid,int num,int op);
int commSemSet(int num,int flags);

comm.c

#include "comm.h"

int commSemSet(int num,int flags)
{
    int _key=ftok(PATHNAME,PROJ_ID);
    if(_key<0)
    {
        perror("ftok");
        return -1;
    }
    int semid=semget(_key,num,flags);
    if(semid<0)
    {
        perror("semget");
        return -2;
    }
    return semid;
}
int creatSemSet(int num)
{
    return commSemSet(num,IPC_CREAT|IPC_EXCL|0666);
}
int initSemSet(int semid,int num,int val)
{
    union semun _un;
    _un.val=val;
    if(semctl(semid,num,SETVAL,_un)<0)
    {
        perror("semctl");
        return -1;
    }
    return 0;
}
int getSemSet(int num)
{
    return commSemSet(num,IPC_CREAT);
}
int destorySemSet(int semid)
{
    if(semctl(semid,0,IPC_RMID)<0)
    {
        perror("semctl");
        return -1;
    }
    return 0;
}
static int comPV(int semid,int num,int op)
{
    struct sembuf _sf;
    _sf.sem_num=num;
    _sf.sem_op=op;
    _sf.sem_flg=0;
    if(semop(semid,&_sf,1)<0)
    {
        perror("semop");
        return -1;
    }
    return 0;
}
int P(int semid,int num)
{
    return comPV(semid,num,-1);
}
int V(int semid,int num)
{
    return comPV(semid,num,1);
}

sem.c

#include "comm.h"
int main()
{
    int semid=creatSemSet(1);
    initSemSet(semid,0,1);
    if(fork()==0)
    {
        int _semid=getSemSet(0);
        while(1)
        {
            P(_semid,0);
            printf("A");
            fflush(stdout);
            sleep(1);
            printf("A");
            fflush(stdout);
            sleep(2);
            V(_semid,0);
        }
    }
    else
    {
        sleep(1);
        while(1)
        {
            P(semid,0);
            printf("B");
            fflush(stdout);
            sleep(2);
            printf("B");
            fflush(stdout);
            sleep(1);
            V(semid,0);
        }
        wait(NULL);
    }

    return 0;
}

没有P/V操作将不能实现成对打印,不能实现进程之间的同步

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值