进程间通信 [2]

5.2 进程间信号量
进程间信号量的分配,使用和解除分配和共享内存段类似。
5.2.1 分配和解除分配
SYNOPSIS
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

       int semget(key_t key, int nsems, int semflg);
描述:    semget()会返回与参数key 相关的信号量集的标识符.
        如果,key 值为 IPC_PRIVATE,
        或者,和key相关的信号量集不存在,并且在 semflg中指定了IPC_CREAT,
        那么,一个有 nsems个信号量的的新集合将被创建。
       
        如果,semflg指定了 IPC_CREAT和 IPC_EXCL,并且与 key 相关的信号量集已经存在,
        那么,semget() 返回 EEXIST.(这与 在 open()中指定了 O_CREAT | O_EXCL 类似。)
       
        semflg的低9位决定了owner,group,others对该信号量集的权限。信号量集的可执行权限是没有意义的。

SYNOPSIS
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

       int semctl(int semid, int semnum, int cmd, ...);
    解除信号量的分配,使用 semctl, semid 为要解除的信号量集的标识符,semnum信号量集中信号量的个数,IPC_RMID 指定了消除操作,第四个参数为
    任何union semun类型的值(这个值是被忽略的,其内容无关紧要)。
    再此处对semctl先不做其他解释。
下面先看一信号量的分配和消除分配的例子,
Listing 5.2 (sem_all_deall.c) Allocating and Deallocating a Binary Semaphore
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
/* We must define union semun ourselves.     */
union semun {
   int val;
   struct semid_ds *buf;
   unsigned short int *array;
   struct seminfo *__buf;
};
/* Obtain a binary semaphore’s ID, allocating if necessary.    */
int binary_semaphore_allocation (key_t key, int sem_flags)
{
   return semget (key, 1, sem_flags);
}
/* Deallocate a binary semaphore. All users must have finished their
    use. Returns -1 on failure. */
int binary_semaphore_deallocate (int semid)
{
   union semun ignored_argument;
   return semctl (semid, 1, IPC_RMID, ignored_argument);
}

5.2.2 进程间信号量的初始化
信号量的分配和初始化是两个相互独立的操作。为了初始化一个信号量,还要使用 semctl,第一参数为 线号量集的标识符,0 作为第二个参数,SETALL作为第三个参数。对于第四个参数,你必须创建一个union semun 类型的对象,并且让的array域指向一个 unsigned short 类型的数组。这个数组中的每个值都是用来初始化信号量集中的一个信号量的。
下面是个初始化一个二值信号量的例子,
Listing 5.3 (sem_init.c) Initializing a Binary Semaphore
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
/* We must define union semun ourselves.   */
union semun {
   int val;
   struct semid_ds *buf;
   unsigned short int *array;
   struct seminfo *__buf;
};
/* Initialize a binary semaphore with a value of 1. */
int binary_semaphore_initialize (int semid)
{
   union semun argument;
   unsigned short values[1];
   values[0] = 1;
   argument.array = values;
   return semctl (semid, 0, SETALL, argument);
}

5.2.3 wait 和 Post 操作
每个信号量都有一个非负的值,支持wait和post操作。系统调用 semop 可以完成这两种操作。第一个参数为一个信号量集的标识符。第二个参数为一个
struct sembuf 类型的数组,它指定了你想要完成的操作。第三个参数为第二个参数数组的长度。
struct sembuf 的每个域如下,
@  sem_num,是信号量集中的信号量的个数。
@    sem_op,是个整数,制定了信号量的操作。
        如果, sem_op 是个正值,那么这个值立即加在信号的值上。
        如果, sem_op 是个非正值,那么从信号量的值中减去这个数的绝对值。如果这样做使得信号量的值为负,那么这次调用将阻塞,直到信号量的值
        变到大于 sem_op的绝对值。(因为其他进程可能会使信号量的值增加。)
@    sem_flg 是个flag值。如果它指定为 IPC_NOWAIT,那么它将使得 semop操作非阻塞。如果一个进程由于调用了semop应当被阻塞,但是因为指定了
    IPC_NOWAIT那么semop将调用失败而返回,却不会阻塞进程。如果指定了SEM_UNDO,Linux自动取消一个退出进程对信号量的操作。

如下为一个二值信号量的 w 和 p 操作示例,
Listing 5.4 (sem_pv.c) Wait and Post Operations for a Binary Semaphore
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
/* Wait on a binary semaphore.   Block until the semaphore value is positive, then
    decrement it by 1. */
int binary_semaphore_wait (int semid)
{
  struct sembuf operations[1];
  /* Use the first (and only) semaphore.   */
  operations[0].sem_num = 0;
  /* Decrement by 1. */
  operations[0].sem_op = -1;
  /* Permit undo’ing. */
  operations[0].sem_flg = SEM_UNDO;
  return semop (semid, operations, 1);
}
/* Post to a binary semaphore: increment its value by 1.
    This returns immediately. */
int binary_semaphore_post (int semid)
{
  struct sembuf operations[1];
  /* Use the first (and only) semaphore.   */
  operations[0].sem_num = 0;
  /* Increment by 1. */
  operations[0].sem_op = 1;
  /* Permit undo’ing. */
  operations[0].sem_flg = SEM_UNDO;
  return semop (semid, operations, 1);
}

补充:
每一个信号量中都有如下相关的值:
@    unsigned short semval;//信号量的值
@    unsigned short semzcnt;//# waiting for zero
@    unsigned short semncnt;//# waiting for increase
@    pid_t                sempid;//最后一个操作信号量的进程的进程ID
...

5.2.4 信号量调试
使用 ipcs -s显示当前系统中存在的信号量集
使用 ipcrm sem semaphore_set_identifier 删除一个存在的信号量集

下面是个完整的例子,例子中,进程A向共享内存写入数据,执行 V 操作,再执行 P 操作,从共享内存读出数据,退出。进程B 中 执行 P 操作,然后从
共享内存中读出数据,再向其中写入数据。然后退出。注意:本程序应先运行A,马上在运行B.示意性的。
//Process A #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/stat.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> /* We must define union semun ourselves */ 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 }; /* Obtain a binary semaphore's ID, allocating if necessary. */ int binary_semaphore_allocation (key_t key, int sem_flags) { return semget (key, 1, sem_flags); } /* Deallocate a binary semaphore. All users must have finished their use. * return -1 on failure. */ int binary_semaphore_deallocate (int semid) { union semun ignored_argument; return semctl (semid, 1, IPC_RMID, ignored_argument); } /* Initialize a binary semaphore with a value of 0. */ int binary_semphore_initialize (int semid) { union semun argument; unsigned short values[1]; values[0] = 0; argument.array = values; return semctl (semid, 0, SETALL, argument); } /* Wait on a binary semaphore. Block until the semaphore value is positive, * then decrement it by 1. */ int binary_semaphore_wait (int semid) { struct sembuf operations[1]; /* Use the first (and only) semaphore. */ operations[0].sem_num = 0; /* Decrement by 1. */ operations[0].sem_op = -1; /* Permit undo'ing. */ operations[0].sem_flg = SEM_UNDO; return semop (semid, operations, 1); } /* Post to a binary semaphore: increment its value by 1. * This returns immediately. */ int binary_semaphore_post (int semid) { struct sembuf operations[1]; /* Use the first (and only) semaphore. */ operations[0].sem_num = 0; /* Increment by 1. */ operations[0].sem_op = 1; /* Permit undo'ing. */ operations[0].sem_flg = SEM_UNDO; return semop (semid,operations, 1); } int main(void) { key_t key; int ret; int semid,shmid; char* shared_memory = NULL; printf("Process A begin./n"); //set key value key = ftok("/",0);//generate key if (key == -1){ fprintf(stderr, "ftok error: %s", strerror(errno)); exit(1); } printf("/tkey is %x/n", (long)key); //allocate semphore semid = binary_semaphore_allocation(key, IPC_CREAT | IPC_EXCL); if (semid < 0){ fprintf(stderr, "allocate error: %s", strerror(errno)); exit(1); } printf("/tsemid is %d/n", semid); //initialize semphore ,value is 1. ret = binary_semphore_initialize (semid); if (ret < 0){ fprintf(stderr, "initialize error: %s", strerror(errno)); exit(1); } //show IPC semphores // system("ipcs -s"); //communicate //create shared memery shmid = shmget(key, getpagesize(),IPC_CREAT | S_IRUSR | S_IWUSR | S_IWOTH | S_IROTH); if ((int)shmid < 0) { fputs("create shared memory error./n", stderr); exit(1); } // shared memory attach shared_memory = (char*) shmat (shmid, 0, 0); if (shared_memory == (void*)EINVAL) { fputs("shared memory attach error./n", stderr); exit(1); } printf("shared_memory is %p./n", shared_memory); sleep(10); //semphore wait //binary_semaphore_wait (semid); //do something sprintf(shared_memory, "/tA1: Hi,my girl.What's your name?/n/0"); //semphore post binary_semaphore_post (semid); //sleep(10); //semphore wait binary_semaphore_wait (semid); //read the content of the shared memory printf("A2:the content of the shared_memory is %s", shared_memory); //deache shared memory shmdt (shared_memory); //deallocate the shared memory segment. shmctl (shmid, IPC_RMID, 0); //deallocate semphore ret = binary_semaphore_deallocate(semid); if (ret < 0) { fprintf(stderr, "deallocate error: %s", strerror(errno)); exit(1); } printf("semphore deallocate success./n"); printf("Process A terminated./n"); return 0; } //Process B #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/stat.h> #include <sys/shm.h> #include <errno.h> #include <sys/types.h> /* We must define union semun ourselves */ 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 }; /* Obtain a binary semaphore's ID, allocating if necessary. */ int binary_semaphore_allocation (key_t key, int sem_flags) { return semget (key, 0/*1*/, sem_flags); } /* Deallocate a binary semaphore. All users must have finished their use. * * return -1 on failure. */ int binary_semaphore_deallocate (int semid) { union semun ignored_argument; return semctl (semid, 1, IPC_RMID, ignored_argument); } /* Initialize a binary semaphore with a value of 0. */ int binary_semphore_initialize (int semid) { union semun argument; unsigned short values[1]; values[0] = 0; argument.array = values; return semctl (semid, 0, SETALL, argument); } /* Wait on a binary semaphore. Block until the semaphore value is positive, * * then decrement it by 1. */ int binary_semaphore_wait (int semid) { struct sembuf operations[1]; /* Use the first (and only) semaphore. */ operations[0].sem_num = 0; /* Decrement by 1. */ operations[0].sem_op = -1; /* Permit undo'ing. */ operations[0].sem_flg = SEM_UNDO; return semop (semid, operations, 1); } /* Post to a binary semaphore: increment its value by 1. * * This returns immediately. */ int binary_semaphore_post (int semid) { struct sembuf operations[1]; /* Use the first (and only) semaphore. */ operations[0].sem_num = 0; /* Increment by 1. */ operations[0].sem_op = 1; /* Permit undo'ing. */ operations[0].sem_flg = SEM_UNDO; return semop (semid,operations, 1); } int main(void) { key_t key; int ret; int semid,shmid; char* shared_memory = NULL; printf("Process B begin./n"); //set key value key = ftok("/", 0);//generate key if (key == -1) { fprintf(stderr, "ftok error: %s", strerror(errno)); exit(1); } printf("/tKey is %x/n", (long)key); //allocate semphore semid = binary_semaphore_allocation(key, 0); if (semid < 0){ fprintf(stderr, "sempahore allocate error: %s./n", strerror(errno)); exit(1); } printf("B: semid is %d /n", semid); //create shared memery shmid = shmget(key, getpagesize(),0); if ((int)shmid < 0) { fputs("create shared memory error./n", stderr); exit(1); } //shared memory attach shared_memory = (char*) shmat (shmid, 0, 0); if (shared_memory == (void*)EINVAL) { fputs("B:shared memory attach error./n",stderr); exit(1); } printf("B: shared_memory is %p./n", shared_memory); //semphore wait binary_semaphore_wait (semid); printf("B:the content of shared_memory is %s", shared_memory); //shared memory write sprintf(shared_memory, "B: Hi,My name is Lucy./n"); //semphore post binary_semaphore_post (semid); //shared memory detach shmdt (shared_memory); printf("Process B terminated./n"); return 0; }

 

你还可以参考:http://blog.csdn.net/liranke/archive/2010/05/15/5595734.aspx

你可能感兴趣的:(linux,struct,Semaphore,null,System,Allocation)