一个包含了信号、信号量、共享内存的例子

    根据《linux网络编程》p117的例子改编的,因为书上的例子有一些错误,这里进行了改正,并增加了利用信号中断程序,回收资源的功能。

#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
/***********************
该文可以任意转载,修改,但需保留出处
修改者:rainfish
出处:http://blog.csdn.net/bat603/
版权归《linux网络编程》所有
*****************/
#define SHMKEY1 (key_t)0x10
#define SHMKEY2 (key_t)0x15

#define SEMKEY  (key_t)0x20

#define SIZ 5*BUFSIZ


#define IFLAGS (IPC_CREAT|IPC_EXCL)
#define ERR ((struct databuf*)-1)



struct sembuf p1 = {0, -1, 0};
struct sembuf v1 = {0, 1, 0};
struct sembuf p2 = {1, -1, 0};
struct sembuf v2 = {1, 1, 0};
static int shmid1, shmid2, semid;

struct databuf
{
  int d_nread;
  char d_buf[SIZ];
};


void
fatal(char *mes)
{
  perror(mes);
  exit (1);
}

void
getshm (struct databuf **p1, struct databuf **p2)
{//创建共享内存
  if ((shmid1=shmget(SHMKEY1, sizeof(struct databuf), 0600|IFLAGS)) < 0)
    {
      fatal ("shmget");
    }

  if ((shmid2=shmget(SHMKEY2, sizeof(struct databuf), 0600|IFLAGS)) < 0)
    {
      fatal ("shmget");
    }
  //映射
  if ((*p1=(struct databuf*)(shmat(shmid1, 0, 0))) == ERR)
    {
      fatal("shmat");
    }

  if ((*p2=(struct databuf*)(shmat(shmid2, 0, 0))) == ERR)
    {
      fatal("shmat");
    }

}

int
getsem()
{
  //int semid;
  if ((semid=semget(SEMKEY, 2, 0600|IFLAGS)) < 0)
    {
      fatal("segmet");
    }
  //初始化信号量,假定第一个信号灯没有资源
  if (semctl(semid, 0, SETVAL, 0) < 0)
    {
      fatal ("semctl");
    }
  //第二个有信息,如果两个信号都没有资源,将会出现死锁
    //书上该处有问题
  if (semctl(semid, 1, SETVAL, 1) < 0)
    {
      fatal ("semctl");
    }

  return (semid);
}

void
myremove()
{
  if (shmctl(shmid1, IPC_RMID, NULL) < 0)
    {
      fatal("shmctl");
    }
  if (shmctl(shmid2, IPC_RMID, NULL) < 0)
    {
      fatal("shmctl");
    }
  if (semctl(semid, 0, IPC_RMID, NULL) < 0)
      fatal("semctl");
  exit(0);
}

void
reader(int semid, struct databuf *buf1, struct databuf *buf2)
{
  for(;;)
    {
      //从键盘读入数据,放在buf1->d_buf,
    //read第一个参数是文件描述符,其中0表示从终端输入:如键盘
      buf1->d_nread = read(0, buf1->d_buf, SIZ);
      //v操作,释放第一个信号灯资源   
      semop(semid, &v1, 1);
      //p操作,申请第二个信号灯资源,若没有资源,则阻塞进程直到有资源.
      semop(semid, &p2, 1);

       buf2->d_nread = read(0, buf2->d_buf, SIZ);

       semop(semid, &v2, 1);
       semop(semid, &p1, 1);
 
    }
      
}

void
writer(int semid, struct databuf *buf1, struct databuf *buf2)
{
  for(;;)
    {
      //p操作,等待第一个信号的资源    
      semop(semid, &p1, 1);
     //1代表输出到屏幕
      write(1, buf1->d_buf, buf1->d_nread);

      semop(semid, &v1, 1);
      semop(semid, &p2, 1);

      write(1, buf2->d_buf, buf2->d_nread);

      semop(semid, &v2, 1);
    }
}

int
main()
{
  int semid, pid;
 
  struct databuf *buf1, *buf2;
 
 
 
  semid = getsem();
  getshm (&buf1, &buf2);

  switch(pid=fork())
    {
    case -1:
      fatal("fork");
      break;
    case 0:
      writer(semid, buf1, buf2);
      break;
    default:
      //在主进程中把中断程序的ctrl+c和myremove函数建立联系,来回收系统资源:共享内存区,信号量.
       signal (SIGINT, myremove);
      reader(semid, buf1, buf2);
      break;
    }
  exit(0);
}
在C语言中,两个进程可以通过共享内存信号量来实现数据的读写操作。共享内存允许两个或多个进程共享一块给定的存储区,这样,进程可以直接对共享的内存块进行读写,而无需数据在进程之间进行复制。信号量则用于同步对共享内存的访问,以防止多个进程同时对同一内存块进行操作,从而导致数据冲突或不一致。 以下是一个简单的例子来说明如何使用共享内存信号量来实现进程间通信: 首先,需要包含头文件 `<sys/shm.h>` 用于共享内存操作, `<sys/sem.h>` 用于信号量操作, `<sys/ipc.h>` 包含共享内存信号量相关的数据类型定义,以及 `<stdlib.h>` 和 `<stdio.h>` 等。 1. 创建和使用共享内存: ```c #include <sys/shm.h> #include <sys/ipc.h> int shm_id; // 共享内存标识符 // 创建共享内存 shm_id = shmget(IPC_PRIVATE, 1024, 0666|IPC_CREAT); // 创建一块大小为1024字节的共享内存 // 将共享内存附加到进程的地址空间 void *shm_ptr = shmat(shm_id, (void *)0, 0); ``` 2. 创建和操作信号量: ```c #include <sys/sem.h> #include <sys/ipc.h> int sem_id; // 信号量标识符 // 初始化信号量 union semun sem_union; sem_id = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT); // 创建一个信号量集合,包含1个信号量 sem_union.val = 1; // 设置信号量的初始值为1,表示共享内存可用 // 设置信号量的值 semctl(sem_id, 0, SETVAL, sem_union); ``` 3. 进程间数据读写和同步: ```c // 写入数据 strcpy(shm_ptr, "Hello, World!"); // P操作(等待) semctl(sem_id, 0, 0); // 将信号量的值减1,如果为0则进程阻塞 // 读取数据 printf("%s\n", (char *)shm_ptr); // V操作(释放) semctl(sem_id, 0, 1); // 将信号量的值加1,如果之前有进程等待此信号量,则唤醒它们 ``` 4. 删除共享内存信号量: ```c // 分离共享内存 shmdt(shm_ptr); // 删除共享内存 shmctl(shm_id, IPC_RMID, NULL); // 删除信号量 semctl(sem_id, 0, IPC_RMID, NULL); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值