进程间通讯(六).semaphore and shared(2)

2021-09-15 20:08:57 浏览数 (1)

shmsemB.c

代码语言:javascript复制
#include <stdio.h>
#include <sys/shm.h>  //shmget,shmat,shmdt 相关声明都在这里
#include <sys/sem.h>  //sembuf, SEM_UNDO,semget,semop 相关声明和宏定义都在这里
#include <string.h>

#define SHMSIZE 1024

typedef struct sembuf SB;  //将sembuf重命名

int main()
{
  int res=-1,shmid=0,semid=0;
  key_t  key=IPC_PRIVATE;
  char *shmaddr=NULL;
  SB sem_v0={0,1,SEM_UNDO},  //构建对第一个信号量进行V操作的参数
     sem_p1={1,-1,SEM_UNDO}; //构建对第二个信号量进行P操作的参数

  if(-1 == (key=ftok("/",888))) //生成key
  {
    perror("ftok");
    return res;
  }
  if (0 > (shmid=shmget(key,SHMSIZE,IPC_CREAT|0600))) //使用key创建或获取共享内存ID,大小为1024字节 or use getpagesize() instead
  {
    perror("shmget");
    return res;
  }
  else printf("created shared memory :%dn",shmid); //将共享内存的ID进行显示
  
  if ((char *)0 > (shmaddr=shmat(shmid,0,0))) //通过共享内存的ID获取内存地址
  {
    perror("shmat");
    return res;
  }
  else printf("attached shared memory:%pn",shmaddr); //将共享内存的地址进行打印
  
  if (0 > (semid=semget(key,2,IPC_CREAT|0600))) //通过key创建两个信号量的ID
  {
    perror("semget");
    return res;
  }
  else printf("created a sem set with two sems which id is :%dn",semid);

  do
  {
    if (0 > semop(semid,&sem_p1,1))  //对第二个信号量进行P操作
    {
      perror("semop"); 
      return res;
    }
    printf("from shm :%s",shmaddr); //将共享内存中的内容进行打印
    
    if(0 == strcmp(shmaddr,"quitn"))break; //如果内容为 quit,则直接退出循环
    if (0 > semop(semid,&sem_v0,1)) //对第一个信号量进行V操作
    {
      perror("semop"); 
      return res;
    }
  }while(1);

  if (0 > (shmdt(shmaddr))) //分享共享内存
  {
    perror("shmdt");
    return res;
  }
  else   printf("Deattach shared-memoryn");
  
  if (0 > semop(semid,&sem_v0,1)) //对第一个信号量进行V操作
  {
    perror("semop"); 
    return res;
  }
  
  res=0;
  return res;
}

编译执行

代码语言:javascript复制
emacs@ubuntu:~/c$ alias gtc
alias gtc='gcc -Wall -g -o'
emacs@ubuntu:~/c$ gtc shmsemA.x  shmsemA.c ; gtc shmsemB.x shmsemB.c 
emacs@ubuntu:~/c$

执行 shmsemB.x 会等待输入

代码语言:javascript复制
emacs@ubuntu:~/c$ ./shmsemB.x 
created shared memory :1081363
attached shared memory:0xb77e1000
created a sem set with two sems which id is :0

执行 shmsemA.x 会等待输入

代码语言:javascript复制
emacs@ubuntu:~/c$ ./shmsemA.x 
created shared memory :1081363
attached shared memory:0xb78b8000
created a sem set with two sems which id is :0
semset has been initialized
please enter the message to shm:
('quit' to exit)

shmsemA.x 端输入一些内容

代码语言:javascript复制
emacs@ubuntu:~/c$ ./shmsemA.x 
created shared memory :1081363
attached shared memory:0xb78b8000
created a sem set with two sems which id is :0
semset has been initialized
please enter the message to shm:
('quit' to exit)
abc
please enter the message to shm:
('quit' to exit)
123
please enter the message to shm:
('quit' to exit)
456
please enter the message to shm:
('quit' to exit)
quit
Deattach shared-memory
Delete shared-memory
emacs@ubuntu:~/c$

shmsemB.x 端会进行显示

代码语言:javascript复制
emacs@ubuntu:~/c$ ./shmsemB.x 
created shared memory :1081363
attached shared memory:0xb77e1000
created a sem set with two sems which id is :0
from shm :abc
from shm :123
from shm :456
from shm :quit
Deattach shared-memory
emacs@ubuntu:~/c$

编译执行过程中没有报错,从结果来看,符合预期


sembuf

sys/sem.h 中有关于sembuf结构体的定义

代码语言:javascript复制
/* Structure used for argument to `semop' to describe operations.  */
struct sembuf
{
  unsigned short int sem_num;   /* semaphore number */
  short int sem_op;             /* semaphore operation */
  short int sem_flg;            /* operation flag */
};

这个结构体定义的其实是 semop 的第二个参数

这个结构体中三个成员变量分别表示 :

  • sem_num 信号在信号集中的索引,0代表第一个信号,1代表第二个信号
  • sem_op 操作类型,代表P操作或是V操作
  • sem_flg 该参数可设置为 IPC_NOWAITSEM_UNDO 两种状态,IPC_NOWAIT 设置信号量操作不等待,一般使用 SEM_UNDO , 代表进程终止或崩溃后,这个操作会自动撤销,恢复到未操作之前的样子,是为了避免进程异常导致的死锁或系统资源耗尽

SEM_UNDO

bits/sem.h 中有关于 SEM_UNDO 宏的定义

代码语言:javascript复制
/* Flags for `semop'.  */
#define SEM_UNDO        0x1000          /* undo the operation on exit */

SEM_UNDO 选项会让内核记录一个与调用进程相关的UNDO记录,如果该进程崩溃,则根据这个进程的UNDO记录自动恢复相应信号量的计数值


shmget

sys/shm.h 中有关于 shmget 的原型声明

代码语言:javascript复制
/* Get shared memory segment.  */
extern int shmget (key_t __key, size_t __size, int __shmflg) __THROW;

得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符

__key 由ftok生成的key

__size 共享内存的大小

__shmflgshmflg&IPC_CREAT 为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符;IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个消息队列;如果存在这样的共享内存则报错(shmflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行或运算(|)来确定信号量集的存取权限)

函数成功则返回共享内存的标识符,出错则返回-1,错误原因存于error中

有以下几种错误

0 人点赞