信号量实现进程间访问互斥的资源测试例子。
主要涉及到的函数及原型如下(加粗、颜色表示要重点关心的上下文相关变量)
1: key_tftok(char *fileName, int id);//目的获取key值
2: intsemget(key_t key, int nsems, int semflg)//目的获取id
3:int semctl(int semid, int semnum, int cmd, union semunarg)//目的设置信号量的值,获取信号量的值等等,功能通过cmd变量控制
//其中semunarg必须由用户自身定义,格式如下
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
//other linux specific
};
4: int semop(int semid, struct sembuf *sops, unsign ednsops)//目的改变信号量的值,在sembuf中。
可通过每个函数大体功能,man手册中查找一些说明,进行研究测试。
以下测试代码非常简单,仅仅是为了熟悉api的基本功能,如果有错误和需要说明的地方,欢迎指正。
#include <sys/types.h>
#include <sys/sem.h>
#include <stdio.h>
#include <errno.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>
union semun {//semctl函数的第三个参数结构定义,现只关心设置val,其它成员可忽视,起到初始化资源数目的作用
int val;
// struct semid_ds *buf;
// unsigned short *array;
// struct seminfo *__buf;
};
int sem_init(int semid, int initval)//初始化信号量 init val
{
union semun arg;
arg.val = initval;
semctl(semid, 0, SETVAL, arg);//SETVAL 是semctl的cmd参数,意思是设置信号量为arg.val的值,0是信号量中第1个资源的下标
//fixme if some error
return 0;
}
int creat_sem(char *fileName)//创建一个信号灯,信号量默认写了1个,如果没有该信号量,创建,如果有,获取id
{
int id;
key_t key;
key = ftok(fileName, 1);
if (key < 0) {
perror("ftok()");
key = 5;//any number just for test
}
if ((id = semget(key, 1, IPC_CREAT | IPC_EXCL |0660)) < 0) {//1个信号量 creat? or exist?
if ((id = semget(key, 1, IPC_CREAT | 0660)) < 0) {//1个信号量 if exist,only get the id
printf("semget error: id = %d\n", id);
}
printf("sem allready exist: id = %d\n", id);
} else {//init the number when first use
sem_init(id, 0);
}
return id;
}
void P(int semid)//申请资源,资源数sembuf中的sem_op - 1
{
int ret = 0;
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = -1;
sb.sem_flg = 0;
ret = semop(semid, &sb, 1);
if (ret < 0) {
printf("error in p(s)\n");
}
}
void V(int semid)//释放资源,资源数sembuf中的sem_op - 1
{
int ret = 0;
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = 1;
sb.sem_flg = 0;
ret = semop(semid, &sb, 1);
if (ret < 0) {
printf("error in v(s)\n");
}
}
void showStat(int semid)
{
int ret = semctl(semid, 0, GETVAL, 0);
printf("now %d val is %d\n", semid, ret);
}
int main(int argc, char **argv)
{
int sem_id0, sem_id1;
if (fork() == 0) {//子进程 进程1
sem_id0 = creat_sem("/tmp/2");
sem_id1 = creat_sem("/tmp/3");
V(sem_id1);
while (1) {
P(sem_id0);
printf("working : process11111\n");
showStat(sem_id0);
showStat(sem_id1);
sleep(1);
V(sem_id1);
}
} else {//父进程 进程2
sem_id0 = creat_sem("/tmp/2");
sem_id1 = creat_sem("/tmp/3");
sleep(2);
while (1) {
P(sem_id1);
printf("working : process2222222222\n");
showStat(sem_id0);
showStat(sem_id1);
sleep(2);
V(sem_id0);
}
}
return 0;
}
主要涉及到的函数及原型如下(加粗、颜色表示要重点关心的上下文相关变量)
1: key_tftok(char *fileName, int id);//目的获取key值
2: intsemget(key_t key, int nsems, int semflg)//目的获取id
3:int semctl(int semid, int semnum, int cmd, union semunarg)//目的设置信号量的值,获取信号量的值等等,功能通过cmd变量控制
//其中semunarg必须由用户自身定义,格式如下
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
//other linux specific
};
4: int semop(int semid, struct sembuf *sops, unsign ednsops)//目的改变信号量的值,在sembuf中。
可通过每个函数大体功能,man手册中查找一些说明,进行研究测试。
以下测试代码非常简单,仅仅是为了熟悉api的基本功能,如果有错误和需要说明的地方,欢迎指正。
#include <sys/types.h>
#include <sys/sem.h>
#include <stdio.h>
#include <errno.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>
union semun {//semctl函数的第三个参数结构定义,现只关心设置val,其它成员可忽视,起到初始化资源数目的作用
int val;
// struct semid_ds *buf;
// unsigned short *array;
// struct seminfo *__buf;
};
int sem_init(int semid, int initval)//初始化信号量 init val
{
union semun arg;
arg.val = initval;
semctl(semid, 0, SETVAL, arg);//SETVAL 是semctl的cmd参数,意思是设置信号量为arg.val的值,0是信号量中第1个资源的下标
//fixme if some error
return 0;
}
int creat_sem(char *fileName)//创建一个信号灯,信号量默认写了1个,如果没有该信号量,创建,如果有,获取id
{
int id;
key_t key;
key = ftok(fileName, 1);
if (key < 0) {
perror("ftok()");
key = 5;//any number just for test
}
if ((id = semget(key, 1, IPC_CREAT | IPC_EXCL |0660)) < 0) {//1个信号量 creat? or exist?
if ((id = semget(key, 1, IPC_CREAT | 0660)) < 0) {//1个信号量 if exist,only get the id
printf("semget error: id = %d\n", id);
}
printf("sem allready exist: id = %d\n", id);
} else {//init the number when first use
sem_init(id, 0);
}
return id;
}
void P(int semid)//申请资源,资源数sembuf中的sem_op - 1
{
int ret = 0;
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = -1;
sb.sem_flg = 0;
ret = semop(semid, &sb, 1);
if (ret < 0) {
printf("error in p(s)\n");
}
}
void V(int semid)//释放资源,资源数sembuf中的sem_op - 1
{
int ret = 0;
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = 1;
sb.sem_flg = 0;
ret = semop(semid, &sb, 1);
if (ret < 0) {
printf("error in v(s)\n");
}
}
void showStat(int semid)
{
int ret = semctl(semid, 0, GETVAL, 0);
printf("now %d val is %d\n", semid, ret);
}
int main(int argc, char **argv)
{
int sem_id0, sem_id1;
if (fork() == 0) {//子进程 进程1
sem_id0 = creat_sem("/tmp/2");
sem_id1 = creat_sem("/tmp/3");
V(sem_id1);
while (1) {
P(sem_id0);
printf("working : process11111\n");
showStat(sem_id0);
showStat(sem_id1);
sleep(1);
V(sem_id1);
}
} else {//父进程 进程2
sem_id0 = creat_sem("/tmp/2");
sem_id1 = creat_sem("/tmp/3");
sleep(2);
while (1) {
P(sem_id1);
printf("working : process2222222222\n");
showStat(sem_id0);
showStat(sem_id1);
sleep(2);
V(sem_id0);
}
}
return 0;
}