Linux学习之进程通信(信号灯)

言之者无罪,闻之者足以戒。 ——《诗序》

信号灯:

命令:ipcs -s查看内核空间的信号灯

下面看一下信号量和信号灯的对比:

功能

信号量(POSOX)

信号量灯(IPC)

定义信号变量

sem_t  sem1

semget

初始化信号量

sem_init

semctl

P操作

sem_wait

semop

V操作

sem_post

semop

信号灯:信号灯集合(可以包含多个信号灯),IPC对象是一个信号灯集(多个信号量)

所有的函数是对一个集合的操作:
1、int semget(key_t key,int nsems,int semflg)创建信号灯函数

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

函数原型

int semget(key_t key, int nsems, int semflg);

函数参数

key:和信号灯集关联的key值,可以用宏定义IPC_PRIVATE,也可以用ftok()函数

 

nsems:  信号灯集中包含的信号灯数目

 

semflg:信号灯集的访问权限

函数返回值

成功:信号灯集ID

 

出错:-1

2、int semctl(int semid ,int semnum ,int cmd ,......union semun arg(不是地址))信号灯的获取、修改、删除函数

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

函数原型

int semctl ( int semid, int semnum,  int cmdunion semun arg(不是地址));

函数参数

semid:信号灯集ID

 

semnum: 要修改的信号灯编号

 

cmd

GETVAL:获取信号灯的值

SETVAL:设置信号灯的值

IPC_RMID:从系统中删除信号灯集合

 

 

函数返回值

成功:0

 

出错:-1

下面我们对比一下三个函数参数的差别:

semctl:cmd

GETVAL:获取信号灯的值

SETVAL:设置信号灯的值

IPC_RMID:从系统中删除信号灯集合

msgctl:cmd

shmctl:cmd

IPC_STAT  (获取对象属性)

IPC_SET (设置对象属性)

SETVAL:设置信号灯的值  信号灯的初始化,类似sem_init;

在这里直接给出程序学习上面两个函数:

#include "sys/types.h"
#include "sys/sem.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
        int semid;
        semid=semget(IPC_PRIVATE,3,0777);
        if(semid < 0)
        {
                printf("creat semaphore failure\n");
                return -1;
        }
        printf("creat semaphore sucess\n");
        system("ipcs -s");


        semctl(semid,0,IPC_RMID,NULL);
        system("ipcs -s");
        return 0;
}

3、int semop(int semid , struct sembuf *opsptr , size_t  nops)信号灯的操作函数

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

函数原型

int semop ( int semid, struct sembuf  *opsptr,  size_t  nops);

函数参数

semid:信号灯集ID

 

struct sembuf {

   short  sem_num;  // 要操作的信号灯的编号

   short  sem_op;   //  0 :  等待,直到信号灯的值变成0

                    // 1 :  释放资源,V操作

                    //   -1 :  分配资源,P操作                    

   short  sem_flg;    // 0,  IPC_NOWAIT,  SEM_UNDO

};

nops:  要操作的信号灯的个数

 

 

函数返回值

成功:0

 

出错:-1

 

上面我们说到了semctl函数,它的第三个参数有三个可选值:GETVAL,SETVAL,IPC_RMID;上次用的是删除也就是IPC_RMID,这次我们用一下设置信号灯值(SETVAL),想要设置信号灯的值就要知道第四个参数union semun arg。

union semun

   {

 int val;   

//SETVAL:设置信号灯的值

 struct semid_ds *buf;

// IPC_STAT  (获取对象属性)

//IPC_SET (设置对象属性)

     unsigned short  *array;  /* Array for GETALL, SETALL */

     struct seminfo  *__buf;  /* Buffer for IPC_INFO (Linux-specific) */

   };

直接给出代码:

#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"
#include "sys/ipc.h"
#include "sys/sem.h"
#include <pthread.h>
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) */
};
int semid;
union semun mysemun;
struct sembuf mysembuf;
void *fun(void *var)//child thread code
{
  int j;
  mysembuf.sem_op=-1;
  semop(semid,&mysembuf,1);
  for(j=0;j<10;j++)//second
  {
    usleep(100);
        printf("this is fun j=%d\n",j);
  }

}
int main()//main thread code
{
  int i;
  char str[]="hello linux\n";
  pthread_t tid;
  int ret;
  semid=semget(IPC_PRIVATE,3,0777);
  if(semid < 0)
  {
        printf("creat semaphore failure\n");
        return -1;
  }
  printf("creat semaphore sucess,semid=%d\n",semid);
  system("ipcs -s");
  mysemun.val=0;
  semctl(semid,0,SETVAL,mysemun);
  //sem_init(&sem,0,0);//sem=0
  mysembuf.sem_num=0;
  mysembuf.sem_flg=0;
  ret=pthread_create(&tid,NULL,fun,(void *)str);
  if(ret<0)
  {
        printf("creat thread failure\n");
        return -2;
  }
  for(i=0;i<10;i++)//first 
  {
        usleep(100);
        printf("this is main fun i=%d\n",i);
  }

  mysembuf.sem_op=1;
  semop(semid,&mysembuf,1);
  while(1);
  return 0;
}

上面的程序编译的时候需要注意的是,它的编译要加上一个后缀-lpthread;命令为:gcc -o sem sem.c -lpthread;如果你没有使用这样的命令编译,那就会有一个错误:undefined reference to `pthread_create';这时候你就用上面我提供的编译命令错误就会消失,然后运行sem就可以看到程序运行的结果。

上一个函数实现的是有亲缘关系的通信,下面给出一个函数实现无亲缘关系的通信,也是进程通信的一个收尾。

实现功能:

(1)创建两个进程server 和client;client进程先运行,server进程后运行

(2)client中的输出信息在server输出信息输出之后才输出,也就是先运行的进程后输出

server函数代码:

#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"
#include "sys/ipc.h"
#include "sys/sem.h"
#include <pthread.h>
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) */
};
int semid;
union semun mysemun;
struct sembuf mysembuf;
int main()//main thread code
{
  int i;
  int key;
  key=ftok("./a.c",'a');
  if(key < 0)
  {
    printf("creat key failure\n");
    return -1;
  }
  printf("creat key scuess\n");
  semid=semget(key,3,IPC_CREAT | 0777);
  if(semid < 0)
  {
        printf("creat semaphore failure\n");
        return -2;
  }
  printf("creat semaphore sucess,semid=%d\n",semid);
  system("ipcs -s");
  mysembuf.sem_num=0;
  mysembuf.sem_flg=0;
  for(i=0;i<10;i++)//first 
  {
        usleep(100);
        printf("this is main fun i=%d\n",i);
  }
 //v  
  mysembuf.sem_op=1;
  semop(semid,&mysembuf,1);
  while(1);
  return 0;
}

client函数的代码:

#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"
#include "sys/ipc.h"
#include "sys/sem.h"
#include <pthread.h>
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) */
};
int semid;
union semun mysemun;
struct sembuf mysembuf; 
int main()//main thread code
{
  int i;
  int key;
  key=ftok("./a.c",'a');
  if(key < 0)
  { 
    printf("creat key failure\n");
    return -1; 
  } 
  printf("creat key scuess\n");
  semid=semget(key,3,IPC_CREAT | 0777);
  if(semid < 0)
  {
        printf("creat semaphore failure\n");
        return -2;
  }
  printf("creat semaphore sucess,semid=%d\n",semid);
  system("ipcs -s");
  //init
  mysemun.val=0;
  semctl(semid,0,SETVAL,mysemun);
  mysembuf.sem_num=0;
  mysembuf.sem_flg=0;
   //P wait
   mysembuf.sem_op=-1;
   semop(semid,&mysembuf,1);
  for(i=0;i<10;i++)//second 
  {
        usleep(100);
        printf("this is second fun i=%d\n",i);
  }

  while(1);
  return 0;
}

到这里为止进程通信的相关知识就全部说完了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值