linux系统编程---进程间的通讯---信号量---学习和记录(五)

管道,消息队列,共享内存,信号都涉及数据,可以进行数据交互;

信号量(钥匙):不涉及数据交互,只管理临界资源 ,用于进程间的互斥与同步;                        临界资源(房间):一次只能允许一个进程使用的资源,需要信号量来管控,如果不去管控则会损坏;

P操作(通过):拿锁                                                                                                                        V操作(释放):放回锁                                                                                                                    信号量集:多个信号量的一个组合;    

函数原型   

1 #include <sys/sem.h>
2 // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
3 int semget(key_t key, int nsems, int semflg);
4 // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
5 int semop(int semid, struct sembuf semoparray[], size_t numops);  
6 // 控制信号量的相关信息
7 int semctl(int semid, int sem_num, int cmd, ...);

  semget函数(创建/获取):                                                                                         

#include <sys/shm.h>
int semget( key_t key, int nsems, int flag);

key:信号标识符                                                                                                                nsens:信号量集中信号量的个数,一般设置1个                                                              flag:指定操作权限,一般设置IPC_CREAT|0666       

semctl函数(初始化信号量): 

int semctl(int semid, int semnum, int cmd, ...);

semid:是semget函数成功返回的ID;                                                                          semunm:信号量集的下标,指定对哪个信号量进行操作,一般只有一个信号量,对第一个信号量进行操作就设置成0;                                                                                    cmd(宏):指定操作类型,一般设置这IPC_RMID, SETVAL等操作                                    SETVAL:用来把信号量初始化为一个已知的值
IPC_RMID:用于删除一个已经无需继续使用的信号量标识符   

配置semctl函数里面的第4个参数:涉及到一个用户自定义的联合体

union semun {
	int              val;    /* Value for SETVAL */ 
    只定义val这个,原先有没有锁,有为1,没有为0
    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) */
};

 semop函数(取/放钥匙函数): 

int semop(int semid, struct sembuf *sops, unsigned nsops);

semid:是semget函数成功返回的ID                                                                                  *sops: 结构体数组指针    

struct sembuf{
    short sem_num; // 除非使用一组信号量,否则它为0
    short sem_op;  // 信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,
                   // 一个是+1,即V(发送信号)操作。
    short sem_flg; // 通常为SEM_UNDO,使操作系统跟踪信号,
                   // 并在进程没有释放该信号量而终止时,操作系统释放信号量
};

 nops:操作*sops结构体数组的个数,只有一个,就不需要定义数组;

函数例子:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
//int semget(key_t key, int nsems, int semflg);
//int semctl(int semid, int semnum, int cmd, ...);
//int semop(int semid, struct sembuf *sops, unsigned nsops);
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) */
};
void pGetKey(int id)
{
    //struct sembuf sops[2];
    struct sembuf sops;
    sops.sem_num = 0;
    sops.sem_op = -1; //钥匙减一
    sops.sem_flg = SEM_UNDO;
    semop(id,&sops, 1);//1表示只有一个
    printf("pGetKey\n");
}
void vPutKey(int id)
{
    //struct sembuf sops[2];
    struct sembuf sops;
    sops.sem_num = 0;
    sops.sem_op = 1; //钥匙加一
    sops.sem_flg = SEM_UNDO;
    semop(id,&sops, 1);//1表示只有一个
    printf("vPutKey\n");
}
int main()
{
    key_t key;
    key = ftok(".",2);
    int semid;
    semid = semget(key,1,IPC_CREAT | 0666);//1表示信号量集有一个信号量,创建信号量

    union semun initsem;
    //initsem.var = 1;   //表示只有一把钥匙
    initsem.val = 0;   //表示没有钥匙了
    semctl(semid,0,SETVAL,initsem);//信号量初始化,0表示操作第0个信号量,
    					//SETVAL用来设置信号量的值设置为initsem

    int pid = fork();
    if(pid > 0){

        pGetKey(semid);//拿钥匙锁
        printf("this is father\n");
        vPutKey(semid);//放钥匙锁
        semctl(semid,0,IPC_RMID); //删除锁
    }
    else if(pid == 0){

        printf("this is child\n");
        vPutKey(semid); //放钥匙,原先没有钥匙,父进程运行时会阻塞,
        				//只有当子进程将钥匙放进去父进程才会运行
    }
    else{
        printf("fork error\n");
    }
    return 0;
}

运行的结果是原先没有锁,子进程先运行,放回一把锁,父进程拿到一把锁,开始运行父进程,然后父进程吧锁放回去,最后删除锁;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值