【簡介】
信號量用於解決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;
};
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>
#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 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;
{
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};
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]);
{
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;
}
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===
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===