linux进程间通信之Posix 信号量用法详解代码举例

Posix信号量不同于System V信号量的信号量集,Posix信号量是单一的信号量,分为有名信号量和无名信号量。
Posix有名信号量是使用Posix IPC名字标示的信号量,可用于进程和线程间的同步;Posix无名信号量是指基于内存的信号量,存放在共享内存区中,用于进程与线程间的同步。

Posix有名信号量可以是内核维护,也可以在文件系统中维护,这取决于信号量对应的路径名是否映射到了真正的磁盘文件上,如果有映射到则在文件系统中维护,否则在内核中维护,Posix有名信号量由函数sem_open(),sem_close(),sem_unlink(),sem_wait(),sem_trywait(),sem_post(),sem_getvalue()来操作使用。

Posix无名信号量根据sem_init()函数调用时的输入参数不同而分为进程间共享和线程间共享,函数原型int sem_init(sem_t *sem,int shared,unsigned int value); 的第二个参数shared若为0,则表示是线程间共享;若shared是1,则表示是进程间共享,同时第一个参数变量sem_t数据类型变量sem必须驻留在所有希望共享它的进程所共享的内存区中。Posix无名信号量由函数sem_init(),sem_destroy(),sem_wait(),sem_trywait(),sem_post(),sem_getvalue()来操作使用。


Posix信号量相关函数的原型及头文件:
#include <semaphore.h>
sem_t *sem_open(const char*name,int oflag,.../*mode_t mode, unsigned int value*/);
功能:创建一个新的有名信号量或打开一个已存在的有名信号量
返回值:若成功返回指向信号量的指针,该指针用作sem_close(),sem_wait(),sem_trywait(),sem_post,sem_getvalue()的参数;若出错返回SEM_FAILED.
参数:name为路径名;oflag可以是0,O_CREAT或O_CREAT|O_EXCL;mode参数可选是指定权限位,在O_CREAT是有效;value参数可选是指定信号量的初始值,不能超过SEM_VALUE_MAX,二值信号量的初始值通常为1,计数信号量初始值通常大于1。

int sem_close(sem_t *sem);
功能:关闭由sem_open()打开的有名信号量。
返回值:若成功返回0,若失败返回-1


int sem_unlink(const char *name);
功能:从系统中真正删除信号量
返回值:若成功返回0,若失败返回-1


int sem_wait(sem_t *sem);
功能:测试指定信号量的值,如果值大于0,则减1并立即返回;如果值等于0,则调用的进程或线程阻塞进入睡眠,直到该值变为大于0,此时会再减1,函数随后返回。这种“测试病减1”的操作必须是原子的。
返回值:成功返回0,出错返回-1


int sem_trywait(sem_t *sem);
功能:与sem_wait()相同,只是当所测试的指定信号量是0时,并不阻塞进入睡眠,而是返回一个EAGAIN错误。
返回值:成功返回0,出错返回-1


int sem_post(sem_t *sem);
功能:把所指定的信号量值加1,然后唤醒正在等待该信号量值变为正数的任意进程或线程。
返回值:成功返回0,出错返回-1


int sem_getvalue(sem_t *sem, int *valp);
功能:获取指定信号量的当前值存入valp指针中,如果信号量已上锁,则获取值为0或某个负数,绝对值是等待该信号量解锁的线程数。
返回值:成功返回0,出错返回-1.


int sem_int(sem_t *sem, int shared, unsigned int value);
功能:初始化Posix共享内存的无名信号量。
返回值: 出错返回-1.
参数:sem是信号量的指针;shared为0是线程共享,为1是进程共享(sem需驻留共享内存);value是初始化值。



int sem_destory(sem_t *sem);
功能:摧毁sem_init()初始化的无名信号量。
返回值:成功返回0,出错返回-1
代码举例,父子进程采用二值信号量sem_test.c:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <unistd.h>
  5. #include <semaphore.h>
  6. #include <fcntl.h>
  7. #define USE_POSIX_SEM 1
  8. #define MYSEM "/mysem"
  9. #define RUN_TIMES 5
  10. int main(void)
  11. {
  12. #if USE_POSIX_SEM
  13.   sem_t *semId;
  14.   int val;
  15.   //sem_unlink(MYSEM);
  16.   semId=sem_open(MYSEM,O_CREAT,0666,0);
  17.   if(SEM_FAILED==semId)
  18.   {
  19.     printf("sem open failed!\n");
  20.     return 0;
  21.   }
  22.   sem_getvalue(semId,&val);
  23.   printf("sem_val init=%d\n",val);
  24.   sem_post(semId);
  25.   sem_getvalue(semId,&val);
  26.   printf("sem_val after post=%d\n",val);
  27. #endif
  28.   int pid=fork();
  29.   if (0==pid)
  30.   {
  31.    int i;
  32.    #if USE_POSIX_SEM
  33.    sem_wait(semId);
  34.    #endif
  35.    for(i=0;i<RUN_TIMES;i++)
  36.    {
  37.    printf("child running!\n");
  38.    sleep(1);
  39.    }
  40.    #if USE_POSIX_SEM
  41.    sem_post(semId);
  42.    #endif
  43.    printf("child end\n");
  44.    exit(0);
  45.   } 
  46.   else if (pid>0)
  47.   {
  48.    int i;
  49.    #if USE_POSIX_SEM
  50.    sem_wait(semId);
  51.    #endif
  52.    for(i=0;i<RUN_TIMES;i++)
  53.    {
  54.     printf("parent running!\n");
  55.     sleep(1);
  56.    }
  57.    #if USE_POSIX_SEM
  58.    sem_post(semId);
  59.    #endif
  60.    printf("parent end\n");
  61.   }
  62.   waitpid(pid,NULL,0);
  63.   printf("progam finished\n");
  64.   #if USE_POSIX_SEM
  65.   sem_close(semId);
  66.   sem_unlink(MYSEM);
  67.   #endif
  68.   return 0;
  69. }
复制代码

运行结果:
$ ./a.out
sem_val init=0
sem_val after post=1
parent running!
parent running!
parent running!
parent running!
parent running!
parent end
child running!
child running!
child running!
child running!
child running!
child end
progam finished

可以看出,父进程先执行,执行5次打印后post 信号量后,子进程才执行。



如果关闭Posix 信号量,条件编译宏设为“#define USE_POSIX_SEM 0”,运行结果为:
$ ./a.out
parent running!
child running!
parent running!
child running!
parent running!
child running!
parent running!
child running!
child running!
parent running!
parent end
child end
progam finished

可以看到父子进程交替执行,存在竞争关系。

猜你喜欢

转载自www.cnblogs.com/wudymand/p/9226476.html
今日推荐