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===
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章