您的位置:首页 > 运维架构 > Linux

进程间通讯之信号量(实例)

2017-04-18 21:58 260 查看

1、信号量

特点:
1、信号量是一个计数器,用于多进程对共享数据对象的访问。
2、信号量的初始值是任一正数,说明有多少个共享资源单位可供共享应用。(常用的信号量形式:初始值为1,即某一资源某一时刻只能给单一进程占有。称为二元信号量或双态信号量)。

控制过程:
①、测试控制该资源的信号量。
②、若信号量的值为正,则进程可以使用该资源。进程将信号量的值减1,表示它使用了一个资源单位。
③、若信号量的值为0,则进程进入休眠状态,直到进程信号量大于1.进程被唤醒,再返回①。
④、当进程不在使用共享资源的时候,该信号量的值+1。若其它有进程等待此信号量,则唤醒它。

应用:
常用于进程的同步,例如多进程项目的log打印或写文件。

2、信号量集

信号量集:信号量的集合
当创建一个信号量集时,要指定该集合中信号量的数量
创建信号量集(semget)与对其赋初值(semctl)应一起,不要分开。

a、创建信号量 或 获取现在存的信号量:
int semget(key_t key,int nsems,int flag)
key:键值
nsems:表示信号量的数量
flag :同msgget

b、操作一个现有的信号量
int semctl(int semid,int semnum,int cmd,.../* union semun arg */)
semid:semget返回的信号量ID

semnum: [0] -- [nsems-1]信号量集合,即有nsems个信号量
c、操作信号量资源
int semop(int semid,struct sembuf semoparray[],size_t nops) //nops 操作几个信号量

3、实例

3.1、semget、semctl

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define    NR     5
#define    OP_ALL

int main(void)
{
int i,ret,semid;
//NR:信号量数组中的信号量个数
semid=semget(0x555,NR,IPC_CREAT|0644);//0x555键值,随便写的一个全局的键值

if(semid==-1)
{
perror("semget");
return 1;
}
printf("semid:%d\n",semid);
//--------------设置信号量值------------------------
#ifndef OP_ALL//逐一赋值
for(i=0;i<NR;i++)
{
ret=semctl(semid,i,SETVAL,1);
if(ret==-1)    return 2;
}
#else//整体赋值
unsigned short  val[NR]={1,1,1,1,1};
ret=semctl(semid,0,SETALL,val);
if(ret==-1)        return 2;//error
#endif //
//---------------get semval-------------------------
#ifndef OP_ALL//逐一获取
for(i=0;i<NR;i++)
{
ret=semctl(semid,i,GETVAL);
if(ret==-1)     return 3;
printf("%dth==>val:%d\n",i,ret);
}
#else//整体获取
unsigned short  temp[NR];
ret=semctl(semid,0,GETALL,temp);
if(ret==-1)        return 3;//error
for(i=0;i<NR;i++)
printf("%dth==>val:%d\n",i,temp[i]);
#endif //
//---------------------------------------------------

getchar();
printf("===============del sem array==========\n");
semctl(semid,0,IPC_RMID);//删除信号量
return 0;
}

3.2、父子进程同步打印字符(semop应用)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define    NR     1
//申请资源
void p_lock(int semid);
//释放资源
void v_unlock(int semid);

int main(void)
{
pid_t pid;
int   ret,semid;

semid=semget(0x555,NR,IPC_CREAT|0644);
if(semid==-1)   return 11;
ret=semctl(semid,0,SETVAL,10);
if(ret==-1)     return 22;
//------------------------------------------
pid=fork();
if(pid==-1)   return 1;
else if(pid==0)  //child
{
char i,*str="1234567890";
for(i=0;str[i];i++)
{
p_lock(semid);
write(STDOUT_FILENO,str+i,1);
usleep(500000);
v_unlock(semid);
}
exit(0);
}
//parent
char i,*str="abcdefghij";
for(i=0;str[i];i++)
{
p_lock(semid);
write(STDOUT_FILENO,str+i,1);
sleep(2);
v_unlock(semid);
}
wait(NULL);
putchar('\n');
return 0;
}
void p_lock(int semid)
{
struct sembuf buf={.sem_num=0,.sem_op=-10};
semop(semid,&buf,1);
}
void v_unlock(int semid)
{
struct sembuf buf={.sem_num=0,.sem_op= 10};
semop(semid,&buf,1);
}


3.3、文件同步写
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

#include <sys/ipc.h>
#include <sys/sem.h>

#define     TIMES    1000000

static int  semid;

void write_file(int fd);

void unlock(void);
void lock(void);

int main(void)
{
int ret,fd,val=0;
pid_t pid;

fd=open("./txt",O_RDWR|O_TRUNC|O_CREAT,0644);
if(fd==-1)   return 1;

pwrite(fd,&val,sizeof(int),0);
//----------------------------------------
semid=semget(0x555,1,IPC_CREAT|0644);//创建一个信号量
if(semid==-1)   return    11;
ret=semctl(semid,0,SETVAL,1);//设置一个信号量,资源为1
if(ret==-1)     return    22;
//-----------------------------------------
pid=fork();
if(pid==-1)   return 2;//error
else if(pid==0)  //child
{
printf("child start......\n");
write_file(fd);
printf("child write file over\n");
close(fd);
exit(0);
}
//parent
printf("parent write file\n");
write_file(fd);
wait(NULL);

pread(fd,&val,sizeof(int),0);
printf("====>val:%d\n",val);

close(fd);
return 0;
}
void write_file(int fd)
{
int i,val;

for(i=0;i<TIMES;i++)
{
//lock
lock();
pread(fd,&val,sizeof(int),0);
val+=1;
pwrite(fd,&val,sizeof(int),0);
unlock();
//unlock
}
}

void lock(void)
{
struct sembuf  buf={.sem_op=-1,.sem_num=0};
semop(semid,&buf,1);
}
void unlock(void)
{
struct sembuf  buf={.sem_op=1,.sem_num=0};
semop(semid,&buf,1);
}

3.4、等0操作

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define    NR       1

void v_unlock(int semid);
void p_lock(int semid);

int main(void)
{
int i,ret,semid;
pid_t  pid;

semid=semget(0x666,NR,IPC_CREAT|0644);
if(semid==-1)   return 1;
ret=semctl(semid,0,SETVAL,10);
if(ret==-1)     return 2;

pid=fork();
if(pid==-1)    return 1;
else if(pid==0) //child
{
while(1)
{
for(i=0;i<10;i++)
{
p_lock(semid);
printf("===child:%d=====\n",i);
sleep(1);
}
}
}
//parent
struct sembuf zero={.sem_num=0,.sem_op=0};
while(1)
{
//wait zero
semop(semid,&zero,1);
printf("==========parent=========\n");
v_unlock(semid);
}

return 0;
}
void v_unlock(int semid)
{
struct sembuf buf={.sem_num=0,.sem_op=10};
semop(semid,&buf,1);
}
void p_lock(int semid)
{
struct sembuf buf={.sem_num=0,.sem_op=-1};
semop(semid,&buf,1);
}

3.5、栅栏程序模型

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#include <signal.h>

#define     NR      5

static int semid;
void sigfunc(int signo)
{
if(signo!=SIGINT)  return;
semctl(semid,0,IPC_RMID);
exit(0);
}
void do_work(int index);
void p_lock(int index);

int main(void)
{
int    i;
pid_t  pid;

signal(SIGINT,sigfunc);//is error

//------create sem-----------------
//对应的信号量用控制对应的子进程 最后一个用于父进程控制周期
semid=semget(0x555,NR+1,IPC_CREAT|0644);
if(semid==-1)
{
perror("semget");
return 1;
}
unsigned short val[NR+1]={0};
i=semctl(semid,0,SETALL,val);
if(i==-1)
{
perror("semctl");
return 2;
}
//-----------------------------------
for(i=0;i<NR;i++)
{
pid=fork();
if(pid==-1)   return 1;
else if(pid==0)//child
{
do_work(i);
exit(0);
}
}
//---------------给定子进程资源---------------
struct sembuf ar[NR+1],zero={.sem_num=NR,.sem_op=0};
for(i=0;i<NR;i++)
{
ar[i].sem_op =1;
ar[i].sem_num=i;
}
ar[NR].sem_num=NR;
ar[NR].sem_op =NR;
//-----------------------------------
while(1)
{
semop(semid,&zero,1);//等0操作
printf("==========================\n");

semop(semid,ar,NR+1);
}

while(wait(NULL)!=-1)
;//empty
return 0;
}

void do_work(int index)
{
int sec;
srand(getpid());
while(1)
{
p_lock(index);
sec=rand()%6+1;
sleep(sec);
printf("%d:[%d] sleep:%d\n",index,getpid(),sec);
//通知父进程已跑完
p_lock(NR);
}
}
void p_lock(int index)
{
struct sembuf  s={.sem_num=index,.sem_op=-1};
if(semop(semid,&s,1)==-1)
{
perror("semop");
exit(1);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息