1. 概述:
该demo主要实现linux下进程之间信号量的使用, 相关接口介绍可以参考<<UNIX环境高级编程>>
2. 测试:
/*
demo_process_IPC_semget.c
进程编程demo(信号量)
IPC相关的命令: ipcs ipcrm(释放IPC)
查看进程属性: ulimit -a
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/sem.h>
/*
头文件 sem.h 把 union semun 声明注释掉了
*/
union semun {
int val;
struct semid_ds *buf;
unsigned short *arry;
};
/*
二元信号量操作
*/
static int Semctl_Init(int semid);
static void Semctl_Deit(int semid);
static int Semop_Down(int semid);
static int Semop_Up(int semid);
#define SEM_ID 1
int main(int argc, char **argv){
int ret;
pid_t pid;
int semid = -1;
key_t key_sem = SEM_ID;
/*
num_sems : 信号量集合数目, 通常它的值为1(二元信号量)
sem_flags : IPC_CREAT | IPC_EXCL, 如果没有该信号量, 则创建, 并返回信号量ID
若已有该信号量, 则返回-1
*/
semid = semget(key_sem, 1, 600 | IPC_CREAT | IPC_EXCL);
if(semid < 0){
/*printf("semget:%s\n", strerror(errno));*/
perror("semget:");
return -1;
}
ret = Semctl_Init(semid);
if(ret < 0){
printf("Semctl_Init error\n");
return -1;
}
pid = fork();
if(pid < 0){
perror("fork:");
Semctl_Deit(semid);
return -1;
}else if(pid == 0){
printf("child process\n"); /*子进程*/
ret = Semop_Down(semid);
if(ret < 0){
printf("Semop_Down error\n");
return -1;
}
printf("child process\t Start\n");
sleep(1);
printf("child process\t Stop\n");
ret = Semop_Up(semid);
if(ret < 0){
printf("Semop_Up error\n");
return -1;
}
}else{
printf("parant process\n"); /*父进程*/
ret = Semop_Down(semid);
if(ret < 0){
printf("Semop_Down error\n");
return -1;
}
printf("parant process\t Start\n");
sleep(1);
printf("parant process\t Stop\n");
ret = Semop_Up(semid);
if(ret < 0){
printf("Semop_Up error\n");
return -1;
}
wait(NULL);
Semctl_Deit(semid);
}
return 0;
}
/*
初始化信号量
*/
static int Semctl_Init(int semid)
{
union semun sem_union;
/*
semnum : 信号量集合的第semnum个信号量
SETVAL : 初始化信号量, 通过union semun中的val成员设置
第四个参数是可选的, 取决于第三个参数
*/
sem_union.val = 1;
if (semctl(semid, 0, SETVAL, sem_union) < 0){
perror("semctl:");
return -1;
}
return 0;
}
/*
删除信号量
*/
static void Semctl_Deit(int semid)
{
/*
semnum : 信号量集合的第semnum个信号量
IPC_RMID : 删除信号量
第四个参数是可选的, 取决于第三个参数
*/
if (semctl(semid, 0, IPC_RMID) < 0){
perror("semctl:");
}
}
/*
获取信号量资源
*/
static int Semop_Down(int semid)
{
struct sembuf sem_b;
sem_b.sem_num = 0; /* 除非使用一组信号量, 否则它为0 */
sem_b.sem_op = -1; /* 若sem_op为负, 表示要获取该信号量控制的资源数
信号量值减去sem_op的绝对值 (P操作) */
sem_b.sem_flg = SEM_UNDO; /* 通常为SEM_UNDO, 使操作系统跟踪信号
即程序结束时(不论正常或不正常), 保证信号值会被重设为semop()调用前的值
这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁, 造成该资源永远锁定 */
if (semop(semid, &sem_b, 1) < 0){
perror("semop:");
return -1;
}
return 0;
}
/*
释放信号量资源
*/
static int Semop_Up(int semid)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1; /* 若sem_op为正, 表示要释放信号量占用的资源数
信号量值加上sem_op的值 (V操作)
附 : 若sem_op为0, 表示将信号量值置为0*/
sem_b.sem_flg = SEM_UNDO;
if (semop(semid, &sem_b, 1) < 0){
perror("semop:");
return -1;
}
return 0;
}
#Makefile
CC := gcc
INCLUDE = -I /home/demo/include/
all:
$(CC) demo_process_IPC_semget.c $(INCLUDE) -o demo_process_IPC_semget -Wall -Werror
clean:
rm demo_process_IPC_shmget