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

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);
    }
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值