您的位置:首页 > 运维架构

semget函数 semopt 采用信号量处理多进程互斥同步

2011-08-01 21:25 399 查看
转自:
http://blog.csdn.net/wbj1234566/article/details/2256629
采用信号量处理多进程互斥同步

信号量与消息类似,也是进程间通信的一种方法。我们在这里讲的信号量,实际上是一个包含信号量元素数组的信号量集。信号量元素与E.W.Dijkstra提出的整数信号量相对应。在一个单系统调用中,进程可在完整的信号量集上操作。

信号量集的内部表示和各自信号量元素不是直接可以访问的,但每个信号量元素必须包括下列各项:

l 一个标识信号量元素的非负整数

l 最后操作信号量元素的进程ID

l 等待信号量元素值加1的进程数

l 等待信号量元素值等于0的进程数

信号量操作允许一个进程阻塞直到信号量元素值为0或者直到它变为正数。每个元素具有两个相关联的队列:一个是等待信号量元素值加1的进程队列,另一个是等待信号量元素值等于0的进程队列。

1、 semget函数

系统调用semget用来创建一个信号量集并将每个元素初始化为0

#include<sys/ipc.h>

#include<sys/sem.h>

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

函数semget有3个参数。第1个参数为标识信号量集的关键字,程序指定关键字的方法有三种:使用IPC_PRIVATE让系统产生一个关键字、挑选一个随机数,或者是使用ftok从文件路径名中产生一个关键字。第2个参数为信号量集中的元素个数。第3个参数为信号量存取权标志与建立标志,该参数的低9位是信号量的存取权标志;建立标志有2个,IPC_CTEAT和IPC_EXCL。IPC_CREAT表示如果信号量集不存在,则创建它; IPC_EXCL表示只有在信号量集不存在的情况下,新的信号量集才会被创建,否则semget返回-1,并设定errno。如果这两个标志联合使用,则功能如同O_EXCL标志于open。

函数semget调用成功时返回一个用于以后semctl等操作的整数句柄,失败时返回-1。

在指定信号量集的关键字时,我们可以使用ftok根据文件路径名产生一个关键字。

#include<sys/ipc.h>

key_t ftok(const char * pathname, int proj_id);

函数ftok的第1个参数为文件路径名,该文件必须存在且进程对该文件有访问权。第2个参数为程序员指定的一个整数ID。该函数成功调用时返回一个关键字,如调用失败,则返回-1。

2、 semctl函数

系统调用semctl可以对信号量进行很多控制。

#include<sys/ipc.h>

#include<sem.h>

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

函数的第1个参数为信号量集的句柄。第2个参数指定信号量集中的元素。第3个参数为执行的控制命令,常见的命令如下表:

命令名称

表示的含义

GETVAL

获得一个指定信号量的值

GETPID

获得操作此元素的最后进程的ID

GETNCNT

获得等待元素增1的进程数

GETZCNT

获得等待元素变为0的进程数

SETVAL

设置一个指定信号量元素的值为arg.val

IPC_RMID

删除一个信号量

IPC_SET

设置信号量的许可权

函数semctl在出现错误时返回-1并设置erro。当调用成功时,其返回值决定于参数cmd,当cmd为GETVAL、GETPID、GETNCNT或GETZCNT时,函数返回相应的值,当cmd为别的值时,返回0。

union senum定义可直接包含在程序中,因为系统的头文件中并没有定义它。它的定义如下:

union senum

{

int val;

struct semid_ds *buf;

ushort *array;

};

union senum中提到的semid_ds结构定义如下:

struct semid_ds

{

struct ipc_perm sem_perm; /*operation permission struct*/

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

time_t sem_ctime; /*last time changed by semctl()*/

struct sem*sembase; /*ptr to first semaphore in array*/

struct sem_queue *sem_pending; /*pending operations*/

struct sem_queue *sem_pending_last; /*last pending operation*/

struct sem_undo *undo; /*undo requests on this array*/

unsigned short int sem_nsems; /*number of semaphores in set*/

};

3、 semop函数

系统调用semop可以对信号量增1、减1或测试其是否为0。

#include <sys/ipc.h>

#include <sys/sem.h>

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

函数semop的第1个参数为semget返回的句柄,第2个参数指向元素操作数组,第3个参数指定在数组中元素操作的个数。

函数成功调用时返回0,失败时返回-1。如果时被信号中断,则返回-1,同时设置errno为EINTR。

结构体sembuf的定义如下:

struct sembuf

{

short int sem_num; //信号量元素个数

short int sem_op; //信号量元素上的操作

short int sem_flg; //操作选项

}

在结构sembuf中,sem_num表示信号量元素的个数,sem_op表示在信号量元素上执行的特别操作,sem_flg表示操作选项的标志。如果sem_op为正数,semop函数将该值加到相应的信号量元素中,并唤醒所有等待元素增1的进程。如果sem_op为0而信号量的值不为0, semop将阻塞调用进程并增加那个元素的等零进程个数。如果sem_op为负数,semop将该值加到相应的信号量元素中(只要结果不为负数),如结果为负数,semop将阻塞进程等待信号量元素值增加;如值为0,semop将唤醒等零进程。

上面的描述假设sem_flg为0。如果sem_flg&IPC_NOWAIT为真,调用不会阻塞,而是返回-1并设置error为 EAGAIN。如果sem_flg&SEM_UNDO为真,函数也将为进程修改信号量的调整值。这个调整值允许进程在退出时恢复它在信号量上的作用。

下面的程序给出了关于信号量集的系统调用semget,semctl和semop的基本用法。

#include <stdio.h>

#include <stdlib.h>

#include <sys/sem.h>

#include <sys/ipc.h>

main()

{

int semid,pid,I,j;

static struct sembuf lock={0,-1,SEM_UNDO};

static struct sembuf unlock={0,1,SEM_UNDO|IPC_NOWAIT};

if((semid=semget(998,1,IPC_CREAT|IPC_EXCL|0666))==-1)

{

printf(“error:semget!/n”);

exit(1);

}

if(semctl(semid,0,SETVAL,1)==-1)

{

printf(“error:semctl!/n”);

exit(1);

}

setbuf(stdout,(char *)NULL);

for(i=0;i<3;i++)

{

if(fork()==0)

{

if((semid=semget(998,1,0))==-1)

{

printf(“error:semget!/n”);

exit(1);

}

for(j=0;j<3;j++)

{

sleep(i);

if(semop(semid,&lock,1)==-1)

{

printf(“error:semop!/n”);

exit(1);

}//if lock

printf(“process %d get into critical section!/n”,getpid());

sleep(1);

printf(“process %d left critical section!/n”,getpid());

if(semop(semid,&unlock,1)==-1)

{

printf(“error:semop!/n”);

exit(1);

}

}//for j

exit(0);

}//if fork

}//for i

for(i=0;i<3;i++)

wait(NULL);

if(semctl(semid,0,IPC_RMID,0)==-1)

{

printf(“error:semctl!/n”);

exit(1);

}

exit(0);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: