Linux进程通信--信号量

Semaphores 信号量

主要用于进程对共享资源的互斥访问。为了取得对一个共享资源,进程测试信号量的值,如果为正,表示还有资源可以访问,该进程对信号量加减一。如果为0表示没有资源可以用,该进程应当休眠等待信号量的值再次为正。

 

Linux中的信号量使用起来是比较麻烦的。在这里,信号量是以集合形式存在的,创建时要给出信号量的数目,并且信号量集合即使没有任何进程访问时,也是存在于系统中的。要注意对其的销毁工作。

每个信号量由以下结构体定义:

struct {

unsigned short  semval; //信号量的值,总是>=0

pid_t  sempid;  //最后一次操作信号量的进程id

unsigned short semncnt; // semval > curval时进程等待

unsigned short semzcnt; //semval == 0时,进程等待

};

每个信号量集合由semid_ds定义:

struct semid_ds {

struct ipc_perm sem_perm;

unsigned short sem_nsems; /* # of semaphores in set */

time_t sem_otime; /* last-semop() time */

time_t sem_ctime; /* last-change time */

};

struct ipc_perm {

uid_t uid; /* owner's effective user id */

gid_t gid; /* owner's effective group id */

uid_t cuid; /* creator's effective user id */

gid_t cgid; /* creator's effective group id */

mode_t mode; /* access modes */

};



获取信号量集合的标识符:

#inlcude <sys/sem.h>

int semget(key_t key,int nsems,int flag);

该函数返回给定键的信号量对应的标识符。键与标识符实际上都指向了该信号量集合,但是标识符只是在该进程内部可见,而键是所有进程都可以使用获取的。如果其他进程也是通过该标识符对信号量集合进行访问,key可以指定为IPC_PRIVATE或者IPC_NEW,比如父子进程的情况。多数情况下,其他进程不方便使用另一进程的标识符,可以调用semget函数指定同一的key,以访问信号量集合。flag在创建的时候低9bit表示权限,和creat创建时需要的权限位定义相同。当flag为0时只表示获取该信号量集合,不进行创建。

 

#include <sys/ipc.h>

key_t ftok(const char *path, int id);

该函数用以创建key。path应当是已经存在的文件,id理解为项目id。注意如果使用同一项目id,对于不同的路径可能会产生相同的key。

 

#include <sysy/sem.h>

int semctl(int semid, int semnum,int cmd,/*union semun arg */);

用以操作信号量集合,semget之后,应该使用semctl进行初始化。

注意下面这个结构体需要由用户自行定义。

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) */
           };
cmd主要有SETVAL IPC_STAT IPC_SET GETALL SETALL GETPID

IPC_RMID 删除该信号量集合。此时正在使用该信号量集合的其他进程对齐操作时会返回EIRM.



#include <sys/sem.h>

int semop(int semid
, struct sembuf semoparray
[],size_t nops
); //原子操作

struct sembuf {

unsigned short sem_num; /* member # in set (0, 1, ..., nsems-1) */

short sem_op; /* operation (negative, 0, or positive) */

short sem_flg; /* IPC_NOWAIT, SEM_UNDO */

};



sem_op 为正:进程释放占用资源,sem_op值加到信号量上去.

为负:如果信号量值大于等于sem_op绝对值,则减去。如果小于,如果指定了IPC_NOWAIT,semop出错返回。如果未指定,则调用进程被挂起,直到符合给定的条件或者信号量被删除/进程从其他信号退出。

为0:表示等待到信号量变为0.



如果在sem_op小于零时指定了SEM_UNDO,即使程终止时未主动释放资源,内核会释放加入SEM_UNDO时占用的资源。



简单的实例代码:

进程a,创建,占用,进程b等待。

#include <sys/ipc.h>

#include <sys/sem.h>

#include <errno.h>

#include <stdio.h>

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 main()

{

key_t sem_key = -1;

if((sem_key = ftok("sem2.tmp",1)) < 0)

{

perror("ftok error");

return -1;

}

int sid = -1;

if((sid = semget(sem_key,1,660)) < 0 )

{

perror("semget error");

return -1;

}



union semun arg = {0};

arg.val = 1;

if(semctl(sid,0,SETVAL,arg.val) < 0)

{

perror("error to set sem");

return -1;

}



struct sembuf arr[1];

arr[0].sem_num = 0;

arr[0].sem_op = -1;

arr[0].sem_flg = 0;



if(semop(sid,arr,1) < 0)

{

perror("semop error");

return -1;

}



sleep(5);



arr[0].sem_op = 1;



if(semop(sid,arr,1) < 0)

{

perror("semop error");

return -1;

}



printf("progam1 over/n");



return 0;

}

//进程b

#include <sys/ipc.h>

#include <sys/sem.h>

#include <errno.h>

#include <stdio.h>



int main()

{



key_t sem_key = -1;

if((sem_key = ftok("sem.tmp",1)) < 0)

{

perror("ftok error");

return -1;

}

int sid = -1;

if((sid = semget(sem_key,1,0)) < 0 )

{

perror("semget error");

return -1;

}



struct sembuf arr[1];

arr[0].sem_num = 0;

arr[0].sem_op = -1;

arr[0].sem_flg = 0;



if(semop(sid,arr,1) < 0)

{

perror("semop error");

return -1;

}



arr[0].sem_op = 1;



if(semop(sid,arr,1) < 0)

{

perror("semop error");

return -1;

}



printf("progam2 over/n");



return 0;

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值