1. 信号量函数的介绍
如果用semget创建了一个新的信号量集对象时,则semid_ds结构成员变量的值设置如下:
sem_otime设置为0。
sem_ctime设置为当前时间。
msg_qbytes设成系统的限制值。
sem_nsems设置为nsems参数的数值。
semflg的读写权限写入sem_perm.mode中。
sem_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。
sops为指向sembuf数组,定义所要进行的操作序列。下面是信号量操作举例。
struct sembuf sem_get={0,-1,IPC_NOWAIT}; /将信号量对象中序号为0的信号量减1/
struct sembuf sem_get={0,1,IPC_NOWAIT}; /将信号量对象中序号为0的信号量加1/
struct sembuf sem_get={0,0,0}; /进程被阻塞,直到对应的信号量值为0/
flag一般为0,若flag包含IPC_NOWAIT,则该操作为非阻塞操作。若flag包含SEM_UNDO,则当进程退出的时候会还原该进程的信号量操作,这个标志在某些情况下是很有用的,比如某进程做了P操作得到资源,但还没来得及做V操作时就异常退出了,此时,其他进程就只能都阻塞在P操作上,于是造成了死锁。若采取SEM_UNDO标志,就可以避免因为进程异常退出而造成的死锁。
参考网址:https://blog.youkuaiyun.com/guoping16/article/details/6584043
2. 示例代码
新建semaphore.h文件
#ifndef __SEM_H__
#define __SEM_H__
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/types.h>
#define PATHNAME "./"
#define PROJ_ID 0x666
union semun
{
int val; //单个信号的值
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
int create_sem_set(int nsem);
int get_sem_set(int nsem);
int init_sem_set(int sem_set_id, int which_sem);
int sem_p(int sem_set_id, int which_sem);
int sem_v(int sem_set_id, int which_sem);
int destroy_sem_set(int sem_set_id);
#endif
新建semaphore.c文件
#include "semaphore.h"
static int sem_set(int nsem, int semflag)
{
key_t key = ftok(PATHNAME, PROJ_ID);
if (key < 0)
{
perror("ftok failure");
exit(-1);
}
int sem_set_id = semget(key, nsem, semflag);
if (sem_set_id < 0)
{
perror("semget failure");
exit(-1);
}
return sem_set_id;
}
int create_sem_set(int nsem)
{
if (nsem <= 0)
{
perror("nsem <= 0");
exit(-1);
}
return sem_set(nsem, IPC_CREAT | IPC_EXCL | 0666);
}
int get_sem_set(int nsem)
{
if (nsem <= 0)
{
perror("nsem <= 0");
exit(-1);
}
return sem_set(nsem, IPC_CREAT);
}
int init_sem_set(int sem_set_id, int which_sem)
{
union semun my_semun;
my_semun.val = 1;//semun中val的值去设置信号集(sem_set)中单个sem的值
int ret = semctl(sem_set_id, which_sem, SETVAL, my_semun);
if (ret == -1)
{
perror("semctl error");
exit(-1);
}
return 0;
}
static int sem_operatons(int sem_set_id, int which_sem, int op)
{
struct sembuf sb;
//sembuf is as follows:
//unsigned short sem_num
//short sem_op
//short sem_flg
sb.sem_num = which_sem;
sb.sem_op = op;
sb.sem_flg = SEM_UNDO;
return semop(sem_set_id, &sb, 1);
}
int sem_p(int sem_set_id, int which_sem)
{
return sem_operatons(sem_set_id, which_sem, -1);
}
int sem_v(int sem_set_id, int which_sem)
{
return sem_operatons(sem_set_id, which_sem, +1);
}
int destroy_sem_set(int sem_set_id)
{
int ret = semctl(sem_set_id, 0, IPC_RMID, NULL);
if (ret == -1)
{
perror("semctl failure");
exit(-1);
}
return ret;
}
新建shm.h文件
#ifndef __SHM__
#define __SHM__
#include<stdlib.h>
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#define PATHNAME "./"
#define PROJ_ID 0x666
int create_shm(int sz);
int get_shm(int sz);
void* malloc_addr(int shm_id);
int free_addr(const void* addr);
int destroy_shm(int shm_id);
#endif
新建shm.c文件
#include"shm.h"
static int shm(int sz, int flag)
{
key_t key = ftok(PATHNAME, PROJ_ID);
if (key == -1)
{
perror("ftok failure");
exit(-1);
}
int shm_id = shmget(key, sz, flag);
if (shm_id < 0)
{
perror("shmget failure");
exit(-1);
}
return shm_id;
}
int create_shm(int sz)
{
return shm(sz, IPC_CREAT | IPC_EXCL | 0666);
}
int get_shm(int sz)
{
return shm(sz, IPC_CREAT);
}
void* malloc_addr(int shm_id)
{
return shmat(shm_id, NULL, 0);
}
int free_addr(const void* addr)
{
return shmdt(addr);
}
int destroy_shm(int shm_id)
{
return shmctl(shm_id, IPC_RMID, NULL);
}
新建test.c文件
#include"shm.h"
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#include"semaphore.h"
typedef struct cPicInfo{
int size;
char state;
}cPicInfo;
typedef struct cPicBuf{
char *picbuf;
int *picbuf_size;
char *picbuf_state; //0 :not use 1: will using 2: is using
}cPicBuf;
#define SHM_SIZE (4096 + sizeof(cPicInfo))
#define PICBUF_NUM (10)
cPicBuf* getfreebuf_frome_mem(char *sharebuf, int perpic_size)
{
int i;
cPicBuf picbuf[PICBUF_NUM];
char *psharebuf = sharebuf + 1;
for( i = 0; i <PICBUF_NUM; i++){
picbuf[i].picbuf = psharebuf + i * SHM_SIZE;
picbuf[i].picbuf_size = (int *)(picbuf[i].picbuf + ( SHM_SIZE - sizeof(cPicInfo)));
picbuf[i].picbuf_state = (char *)(picbuf[i].picbuf_size) + sizeof(int);
if(*picbuf[i].picbuf_state == 0){
*picbuf[i].picbuf_state = 2;
break;
}
}
printf("get free i:%d\n",i);
return i < PICBUF_NUM ? &picbuf[i] : NULL;
}
cPicBuf* getcolbuf_frome_mem(char *sharebuf, int perpic_size)
{
int i;
cPicBuf picbuf[PICBUF_NUM];
char *psharebuf = sharebuf + 1;
for( i = 0; i <PICBUF_NUM; i++){
picbuf[i].picbuf = psharebuf + i * SHM_SIZE;
picbuf[i].picbuf_size = (int *)(picbuf[i].picbuf + ( SHM_SIZE - sizeof(cPicInfo)));
picbuf[i].picbuf_state = (char *)(picbuf[i].picbuf_size) + sizeof(int);
if(*picbuf[i].picbuf_state == 2){
*picbuf[i].picbuf_state = 3;
break;
}
}
printf("get col i:%d\n",i);
return i < PICBUF_NUM ? &picbuf[i] : NULL;
}
int main()
{
int ret;
//创建信号量并初始化
int sem_set_id = create_sem_set(2);
init_sem_set(sem_set_id, 0);
init_sem_set(sem_set_id, 1);
//创建共享内存
int shm_id = create_shm(SHM_SIZE * PICBUF_NUM + 1);
//创建子进程
pid_t pid = fork();
if (pid < 0)
{
perror("fork failure");
exit(-1);
}
else if (pid == 0) //子进程
{
char* buf = (char*)malloc_addr(shm_id);
int count = 0;
cPicBuf* freebuf;
buf[0] = 1;
while(1)
{
//if(buf[0] == 1){ int ret = semctl(sem_set_id, which_sem, SETVAL, my_semun);
if( 1 == (ret =semctl(sem_set_id, 1, GETVAL, NULL))){
printf("zi ret: %d\n", ret);
; count++;
sem_p(sem_set_id, 0);
freebuf = getfreebuf_frome_mem(buf, SHM_SIZE);
if(freebuf != NULL)
*freebuf->picbuf_size = count;
buf[0] = 2;
sem_v(sem_set_id, 0);
sem_p(sem_set_id, 1);
}
if(count == 10)
break;
}
free_addr(buf);
}
else //父进程
{
char* buf = (char*)malloc_addr(shm_id);
//usleep(500000);//让子进程先P操作
cPicBuf* colbuf;
int count1 = 0;
while(1)
{
//if(buf[0] == 2){
if( 0 == (ret = semctl(sem_set_id, 1, GETVAL, NULL))){
printf("fu ret: %d\n", ret);
count1++;
sem_p(sem_set_id, 0);
colbuf = getcolbuf_frome_mem(buf, SHM_SIZE);
if(colbuf != NULL)
{
printf("picbuf_size :%d \n",*colbuf->picbuf_size);
}
buf[0] = 1;
sem_v(sem_set_id, 0);
sem_v(sem_set_id, 1);
}
if(count1 == 10)
break;
}
free_addr(buf);
destroy_shm(shm_id);
destroy_sem_set(sem_set_id);
}
return 0;
}
新建Makefile文件
test:test.c semaphore.c shm.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f test