Linux应用程序Semophore 操作

来源:互联网 发布:写真机蒙泰软件 编辑:程序博客网 时间:2024/06/13 02:32
semget() 
创建一个新的信号量集,或者使用一个已经存在的信号量集。
系统调用:semget();
原型:int semget(key_t key, int nsems, int semflg);
参数:第一个参数是关键字值(一般是由系统调用ftok()返回的)。
第二个参数nsems指出一个新的信号量集合中应该创建的信号量的个数。可以将信号量集合理解为数组,长度为nsems。最大个数定义在linux/sem.h,我的ubuntu8中最大个数为250
返回值:如果成功,则返回信号量集的IPC标识符。如果失败,则返回-1。
errno不再描述。

semop() 
信号量操作
调用原型:int semop(int semid, struct sembuf *sops,unsigned nsops);
参数:第一个参数是关键字值,由semget返回得来。第二个参数是指向将要操作的数组的指针。第三个参数是数组中的操作的个数。nsops为数组sops的大小。
第二个参数结构体如下:
struct sembuf {
    unsigned short      sem_num;        /* 使用第sem_num个信号量 */
    short            sem_op;        /* 信号量操作 */
    short            sem_flg;        /* 操作标志 */
};
sem_num对应信号集中的信号灯,0对应第一个信号灯。sem_flg可取IPC_NOWAIT以及SEM_UNDO两个标志。如果设置了SEM_UNDO标志,那么在进程结束时,相应的操作将被取消,这是比较重要的一个标志位。如果设置了该标志位,那么在进程没有释放共享资源就退出时,内核将代为释放。sem_op的值大于0,等于0以及小于0确定了对sem_num指定的信号灯进行的三种操作。
sem_op>0:相应进程要释放sem_op数目的共享资源;
sem_op=0:用于对共享资源是否已用完的测试;
sem_op<0:进程要申请-sem_op个共享资源。
个人理解:某进程要使用某资源时,先判断sem_op是否为0,然后设定sem_op>0,使用完后sem_op<0。
返回值:0,成功。-1,失败。
errno不再描述。

semctl() 
实现对信号灯的各种控制操作。
系统调用:semctl();
原型:int semctl(int semid, int semnum, int cmd, union semunarg);
参数:
参数semid指定信号灯集,参数semnum指定对哪个信号灯操作,参数cmd指定具体的操作类型,只对几个特殊的cmd操作有意义;semunarg用于设置或返回信号灯信息,代表一个semun实例,该参数可以忽略。
参数cmd中可以使用的命令如下:
    ·IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
    ·IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
    ·IPC_RMID将信号量集从内存中删除。
    ·GETALL用于读取信号量集中的所有信号量的值。
    ·GETNCNT返回正在等待资源的进程数目。
    ·GETPID返回最后一个执行semop操作的进程的PID。
    ·GETVAL返回信号量集中的一个单个的信号量的值。
    ·GETZCNT返回这在等待完全空闲的资源的进程数目。
    ·SETALL设置信号量集中的所有的信号量的值。
    ·SETVAL设置信号量集中的一个单独的信号量的值。

返回值:如果成功,则为一个正数。


===================================================================================================================

当我们使用共享内存时,必然要面对一个问题:并发。信号量可以控制共享资源的申请和释放,起到锁的目的,有效的解决了并发带来的种种问题。

共享内存的使用见《linux下C语言编程4-使用共享内存实现进程间通信2》。

信号量的函数见《linux下C语言编程6-信号量函数semget() semop() semctl() 》。

下面给出一个例子:

服务端:

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/sem.h>#include <sys/ipc.h>#define SEGSIZE 1024// 生成信号量int sem_create(key_t key){int semid;semid = semget(key, 250, IPC_CREAT|0666);if (semid == -1){printf("create semaphore error/n");exit(0);}semctl(semid,0,SETVAL);return semid;}//删除信号量void del_sem(int semid){semctl(semid,0,IPC_RMID);}//pint p(int semid) {/*sembuf第2个参数sem_op:如果其值为正数,该值会加到现有的信号内含值中。通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。*/  struct sembuf sops = {1,-1,SEM_UNDO};// sops数组大小为1  return semop(semid,&sops,1);}//vint v(int semid) {  struct sembuf sops = {1,+1,SEM_UNDO};return semop(semid,&sops,1);}int main(){key_t key;int shmid,semid;char *shm;char msg[32] = "xiaoshe-";char i;struct semid_ds buf;key = ftok("/",0);shmid = shmget(key,SEGSIZE,IPC_CREAT|0604);if (-1 == shmid){printf(" create shared memory error/n");return -1;}printf("shmid = %d/n", shmid);shm = (char *)shmat(shmid, 0, 0);if (-1 == (int)shm){printf(" attach shared memory error/n");return -1;}semid = sem_create(key);printf("semid = %d/n", semid);for (i=0; i<3; i++){sleep(2);p(semid);printf("[%d] p ", i);fflush(stdout);sleep(1);// 修改共享内存msg[8] = '0' + i;memcpy(shm, msg, 32);printf("-> wirte ");fflush(stdout);sleep(3);v(semid);printf("-> v/n");}shmdt(shm);shmctl(shmid,IPC_RMID,&buf);del_sem(semid);return 0;//gcc -o s s.c -g}

客户端:

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/sem.h>#include <time.h>#include <sys/ipc.h>#define SEGSIZE 1024//创建信号量int get_sem(key_t key){int semid;semid = semget(key,20,0);if (-1 == semid){printf("create semaphore error/n");exit(1);}return semid;}//等待信号量变成0void wait_v(int semid){struct sembuf sops={1,0,0};semop(semid,&sops,1);}int main(void){key_t key;int shmid, semid;char *shm;char msg[100];char i;key = ftok("/",0);shmid = shmget(key,SEGSIZE,0);if(-1 == shmid){printf(" create shared memory error/n");return -1;}shm = (char *)shmat(shmid,0,0);if (-1 == (int)shm){printf(" attach shared memory error/n");return -1;}semid = get_sem(key);printf("semid = %d/n", semid);for (i=0; i<4; i++){sleep(1);wait_v(semid);printf("[%d] msg = '%s'/n", i, shm);}shmdt(shm);return 0;// gcc -o c c.c }



0 0
原创粉丝点击