信号量概念
Dijkstra提出的“信号量”概念是共发程序设计领域的一项重大进步 信号量是一种变量,它只能取正整数值,对这些正整数只能进行两种操作:等待和信号 用两种记号来表示信号量的这两种操作: P(semaphore variable) 代表等待 V(semaphore variable) 代表信号
信号量操作
首先我们对信号量进行封装:
//对信号量中要用到的联合体进行声明
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
}
//错误打印
void error_exit(char *errorinfo)
{
printf("%s\n",errorinfo);
exit(EXIT_FAILURE);
}
//信号量创建
int sem_create(key_t key,int nsems)
{
int semid = semget(key,nsems,IPC_CREAT|0766);
if(semid <0)
{
error_exit("creat sem error");
}
return semid;
}
//信号量的打开
int sem_myopen(key_t key)
{
int semid = semget(key,0,0);
if(semid <0)
{
error_exit("creat sem error");
}
return semid;
}
//信号量删除
int sem_delete(int semid)
{
int ret = semctl(semid,0,IPC_RMID);
if(ret<0)
{
error_exit("delete sem error");
}
return ret;
}
//信号量设置里面的值
int sem_setval(int semid,int nsempos,int val)
{
union semun arg;
arg.val=val;
int ret=semctl(semid,nsempos,SETVAL,arg);
if(ret<0)
{
error_exit("set value error");
}
return ret;
}
//信号量获取里面的值
int sem_getval(int semid,int nsempos)
{
int value=semctl(semid,nsempos,GETVAL);
if(value<0)
{
error_exit("get value error");
}
return value;
}
//信号量设置
int sem_setall(int semid,unsigned short*values)
{
union semun arg;
arg.array=values;
int ret=semctl(semid,0,SETVAL,values);
if(ret<0)
{
error_exit("set all error");
}
return ret;
}
//信号量获取
int sem_getall(int semid,unsigned short*values)
{
union semun arg;
arg.array=values;
int ret=semctl(semid,0,GETVAL,values);
if(ret<0)
{
error_exit("set all error");
}
return ret;
}
//信号量V操作
int sem_v(int semid,int npos)
{
struct sembuf buf={npos,1,0};
int ret=semop(semid,&buf,1);
if (ret<0)
{
error_exit("sem p error");
}
return ret;
}
//信号量P操作
int sem_p(int semid,int npos)
{
struct sembuf buf={npos,-1,0};
int ret=semop(semid,&buf,1);
if (ret<0)
{
error_exit("sem p error");
}
return ret;
}
简单使用上面封装的函数实现 父子进程上锁
int main()
{
int semid= sem_create((key_t)0002,1);
sem_setval(semid,0,0);
int pid =fork();
//父进程
if(pid>0)
{
while(1)
{
printf("parent working\n");
sleep(5);
sem_v(semid,0);
}
}
//子进程
else if(pid==0)
{
while(1)
{
printf("child wait\n");
sem_p(semid,0);
printf("child working\n");
}
}
else
{
perror("fork error\n");
}
return 0;
}
实现结果:(每次执行完一个进程才会执行下一个进程,可用于两进程协同处理事情的时候进行使用)
使用以上封装的函数实现多进程p和v的操作
int main()
{
int semid=sem_create((key_t)0001,1);
sem_setval(semid,0,10);
fork();
fork();
fork();
fork();
fork();
fork();
sleep(1);
printf("my name is %d\n",getpid());
sem_p(semid,0);
printf("%d get\n",getpid());
sleep(5);
printf("%d done\n",getpid());
sem_v(semid,0);
return 0;
}
结果:
上面结果:fork6次,总共64个进程,如同64个人练车一样,但是只有10辆车(set_value的第三个参数设置了10),使用p操作代表车被用了一辆,v代表车使用完让出来给别人用,这就是生产者和消费者模型,进行资源保护