POSIX IPC之信号量

【简介】
信号量用于解决2个或者多个进程访问共享资源的问题。
几个主要函数:
(1)int  semget(key_t key,int nsems,int flag);
信号量和消息队列、共享内存都是需要先通过ftok获得一个key,再用对应的函数进行创建,返回IPC标识符。nsems表示信号量集合中的信号个数,flag为可选参数。函数执行失败返回负1.
(2)int  semctl(int semid,int semnum,int cmd,union semun *arg);
该函数用于在一组信号量上做各种控制操作:比如信号集合初始化,状态查询等等。信号量创建时初值不确定,可以使用SETVAL或者SETALL来创建,区别在于如果cmd为SETALL,semnum为信号量集合中的信号总数;如果为SETVAL,semnum为信号量元素编号。
(3)int semop(int semid,struct sembuf semoparray[], int nops);
用于对信号量集合中的一个或者多个信号进行操作,操作命令由用户提供的结构体决定,结构体定义如下:
struct    sembuf{
short    sem_num;    
short    sem_op;    
short    sem_flg;    
};
sem_flg如果为SEM_UNDO,表示如果进程执行的信号量操作锁住了某些资源,而没有释放就返回了,那么进程退出以后,由系统撤销进程做过操作对信号量的影响。
 
【代码】
函数功能:由命令行参数决定创建子进程个数,每个子进程要访问2次临界资源才可以退出。
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
//semctl()的arg结构体
union semun{
 int val;
 struct semid_ds *buf;
 unsigned short int *array;
 struct seminfo *__buf;
};
int main(int argc,char* argv[])
{
 int num;
 int sem_id;
 pid_t pid;
 int i,j;
 int prj_id = 3;
 key_t key;
 
 union semun arg;
//-1表示要申请资源,1表示要释放资源
 static struct sembuf acquire = {0,-1,SEM_UNDO};   
 static struct sembuf release = {0,1,SEM_UNDO};
//需要带一个参数执行,表示创建子进程个数
 if(argc != 2)
 {
  printf("Usage: %s child_process_num.\n",argv[0]);
  return 1;
 }
 num = atoi(argv[1]);
//首先也必须通过ftok获得一个key,才可以用于信号量标识符的创建,创建以后,其他进程可以用这个key访问信号量,获得sem_id
 key = ftok("/home/gaolu",prj_id);
 if(-1 == key)
 {
  perror("Can't generate the IPC key.\n");
  return 1;
 }
 
 sem_id = semget(key,1,IPC_CREAT|IPC_EXCL|0666);
 if(-1 == sem_id)
 {
  perror("Can't creat semaphore set.\n");
  return 1;
 }
 
 static unsigned short init_value = 1;
 arg.array = 1;
 if(semctl(sem_id,0,SETVAL,arg)==-1)
 {
  perror("Can't set semaphore set.\n");
  return 1;
 }
 
 for(i=0;i<num;i++)
 {
  pid = fork();
  if(-1 == pid)
  {
   perror("Fail to creat child process.\n");
   return 1;
  }
  else if(pid == 0)
  {
   sem_id = semget(key,1,0);  //在子进程中获得sem_id
   if(sem_id == -1)
   {
    perror("Child can't get access right.\n");  
    _exit(1);
   }
   for(j=0;j<2;j++)
   {
    sleep(i);
    if(semop(sem_id,&acquire,1)==-1)
    {
     perror("Can't acquire resource.\n");
     _exit(1);
    }
    printf("===Enter the critical section===\n");
    printf("---pid: %ld---\n",(long)getpid());
    sleep(1);
    printf("===Leave the critical section===\n");
    printf("\n\n");
    if(semop(sem_id,&release,1)==-1)
    {
     perror("Can't release resource.\n");
     _exit(1);
    }
   }
   _exit(0);
  }
 }
 for(i=0;i<num;i++)
 {
  wait(NULL);
 }
 if(semctl(sem_id,0,IPC_RMID,0)==-1)
 {
  perror("Can't delete the semaphore set.\n");
  return 1;
 }
 return 0;
 
}

执行结果:
gaolu@gaolu-desktop:~$ gcc -o sema systemcall2.c
systemcall2.c:48: warning: assignment makes pointer from integer without a cast
gaolu@gaolu-desktop:~$
gaolu@gaolu-desktop:~$
gaolu@gaolu-desktop:~$
gaolu@gaolu-desktop:~$
gaolu@gaolu-desktop:~$ ./sema 5   //结果是比较随机滴
===Enter the critical section===
---pid: 5862---
===Leave the critical section===

===Enter the critical section===
---pid: 5863---
===Leave the critical section===

===Enter the critical section===
---pid: 5862---
===Leave the critical section===

===Enter the critical section===
---pid: 5864---
===Leave the critical section===

===Enter the critical section===
---pid: 5865---
===Leave the critical section===

===Enter the critical section===
---pid: 5863---
===Leave the critical section===

===Enter the critical section===
---pid: 5866---
===Leave the critical section===

===Enter the critical section===
---pid: 5864---
===Leave the critical section===

===Enter the critical section===
---pid: 5865---
===Leave the critical section===

===Enter the critical section===
---pid: 5866---
===Leave the critical section===

gaolu@gaolu-desktop:~$

你可能感兴趣的:(职场,ipc,信号量,休闲)