头部互动开始 -->

A申请共享内存并对信号量进行初始化,然后进程B与C实现互斥

练习:设计一个程序,作为进程 A,进程A专门创建一个信号量集,要求信号量集中有1个信号量,对信号量集合中的信号量进行设置,要求集合中的信号量的初值为1,然后再设计2 个程序,分别是进程B和进程C,要求进程B和进程C使用进程A创建的信号量集合中的信号量实现互斥访问。提示:进程 A、进程 B、进程C需要使用共享内存作为临界资源的访问。

进程A:

注意事项:假定sleep模拟的是程序的运行时间。如果在A或者B的sleep时间内,终止运行,会导致B或者C未能进行V操作,导致B和C都不能再次进行。此时需要重新执行A进程来对内存空间里面的数据初始化

/********************************************************************
*          
*          file name:       shm_a.c
*          author:         15070884254@163.com 
*          date:            2024年5月27日
*          function:        新建一个共享内存,并初始化为0。

*          note:          假定sleep模拟的是程序的运行时间。如 果在A或者B的sleep时间内,终止运行,会导致B或者C未能进行V操作,导致B和C都不能再次进行。此时需要重新执行A进程来对内存空间里面的数据初始化
*
*        CopyRight (c)      15070884254@163.com      All Right Reseverd     
*          
********************************************************************/
#include <stdio.h>

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <string.h>

/*****************************************************************************
*                 函数名称:     main
*                 函数功能:    创建一个信号量,并对信号量初始化。创建一个共享内存,并初始化为0。
*                 函数参数:	  int argc, char const *argv[]
*                 返回结果:    NONE
*                 注意事项:    NONE
*                 函数作者:    15070884254@163.com 
*                 创建日期:    2024年5月28日
*                 修改历史:    2024年5月28日
*                 函数版本:    1.0
*
*****************************************************************************/

int main(int argc, char const *argv[])
{
  int *shm_a;

  // 创建一个信号量
  int sem_id = semget(ftok(".", 1), 1, IPC_CREAT | IPC_EXCL | 0664);
  if (sem_id == -1) // 如果信号量存在,则直接打开
  {
    fprintf(stderr, "semget warning: errno: %d, %s\n", errno, strerror(errno));

    sem_id = semget(ftok(".", 1), 1, 0664);
    if (sem_id == -1) // 打开失败直接退出程序
    {
      fprintf(stderr, "semget error, errno: %d, %s\n", errno, strerror(errno));
      exit(1);
    }
  }

  // 设置信号量,并初始化
  struct sembuf sops;
  sops.sem_num = 0;
  sops.sem_op = 1;
  sops.sem_flg = 0;

  if (semop(sem_id, &sops, 1) == -1)
  {
    fprintf(stderr, "semop error, errno: %d, %s\n", errno, strerror(errno));
    exit(1);
  }

  // 创建共享内存
  int shm_id = shmget(ftok(".", 2), 4, IPC_CREAT | IPC_EXCL | 0664);
  if (shm_id == -1) // 如果共享内存存在,则直接打开
  {
    fprintf(stderr, "shmget warning: errno: %d, %s\n", errno, strerror(errno));

    shm_id = shmget(ftok(".", 2), 4, 0664);
    if (shm_id == -1) // 打开失败直接退出程序
    {
      fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
      exit(1);
    }
  }

  // 将共享内存连接到当前进程的地址空间
  shm_a = (int *)shmat(shm_id, NULL, 0);
  if (shm_a == (int *)(-1)) // 连接失败直接退出程序
  {
    fprintf(stderr, "shmat error, errno: %d, %s\n", errno, strerror(errno));
    exit(1);
  }

  // 对共享内存空间进行初始化
  *shm_a = 0;

  // 分离共享内存
  if (shmdt(shm_a) == -1)
  {
    fprintf(stderr, "shmdt error, errno: %d, %s\n", errno, strerror(errno));
    exit(1);
  }

  return 0;
}

进程B:

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <string.h>

/*****************************************************************************
*                 函数名称:     P
*                 函数功能:    对信号量进行P操作(-1+sops.sem_op)
*                 函数参数:	  int sem_id, struct sembuf *sops
*                 返回结果:    NONE
*                 注意事项:    NONE
*                 函数作者:    15070884254@163.com 
*                 创建日期:    2024年5月28日
*                 修改历史:    2024年5月28日
*                 函数版本:    1.0
*
*****************************************************************************/

static void P(int sem_id, struct sembuf *sops)
{
  sops->sem_op = -1;
  if (semop(sem_id, sops, 1) == -1)
  {
    fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
    exit(1);
  }
}

/*****************************************************************************
*                 函数名称:     V
*                 函数功能:    对信号量进行V操作(1+sops.sem_op)
*                 函数参数:	  int sem_id, struct sembuf *sops
*                 返回结果:    NONE
*                 注意事项:    NONE
*                 函数作者:    15070884254@163.com 
*                 创建日期:    2024年5月28日
*                 修改历史:    2024年5月28日
*                 函数版本:    1.0
*
*****************************************************************************/
static void V(int sem_id, struct sembuf *sops)
{
  sops->sem_op = 1;
  if (semop(sem_id, sops, 1) == -1)
  {
    fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
    exit(1);
  }
}

/*****************************************************************************
*                 函数名称:     main
*                 函数功能:    通过对信号量进行PV操作,如果信号量小于0,则阻塞等待,如果大于0,则执行写操作
*                 函数参数:	  int sem_id, struct sembuf *sops
*                 返回结果:    NONE
*                 注意事项:    NONE
*                 函数作者:    15070884254@163.com 
*                 创建日期:    2024年5月28日
*                 修改历史:    2024年5月28日
*                 函数版本:    1.0
*
*****************************************************************************/
int main(int argc, char const *argv[])
{
  // 获取信号量id
  int sem_id = semget(ftok(".", 1), 1, 0664);
  if (sem_id == -1) // 获取失败直接退出程序
  {
    fprintf(stderr, "semget error, errno: %d, %s\n", errno, strerror(errno));
    exit(1);
  }

  // 打开共享队列
  int shm_id = shmget(ftok(".", 2), 4, 0664);
  if (shm_id == -1) // 获取失败直接退出程序
  {
    fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
    exit(1);
  }

  // 获取共享内存的映射地址
  int *shm_ptr = (int *)shmat(shm_id, NULL, 0);

  int i = 0;
  // 设置信号量buf
  struct sembuf sops;
  while (1)
  {
    // 初始化buf
    memset(&sops, 0, sizeof(sops));

    P(sem_id, &sops); // 执行操作前先‘P’一下

    memcpy(shm_ptr, &i, sizeof(int)); // 执行写操作

    sleep(10);

    V(sem_id, &sops); // 执行操作前先‘V’一下

    i++;
    printf("修改i的值: %d\n", i);
  }

  return 0;
}

进程C:

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <string.h>

/*****************************************************************************
 *                 函数名称:     P
 *                 函数功能:    对信号量进行P操作(-1+sops.sem_op)
 *                 函数参数:	  int sem_id, struct sembuf *sops
 *                 返回结果:    NONE
 *                 注意事项:    NONE
 *                 函数作者:    15070884254@163.com
 *                 创建日期:    2024年5月28日
 *                 修改历史:    2024年5月28日
 *                 函数版本:    1.0
 *
 *****************************************************************************/

static void P(int sem_id, struct sembuf *sops)
{
  sops->sem_op = -1;
  if (semop(sem_id, sops, 1) == -1)
  {
    fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
    exit(1);
  }
}

/*****************************************************************************
 *                 函数名称:     V
 *                 函数功能:    对信号量进行V操作(1+sops.sem_op)
 *                 函数参数:	  int sem_id, struct sembuf *sops
 *                 返回结果:    NONE
 *                 注意事项:    NONE
 *                 函数作者:    15070884254@163.com
 *                 创建日期:    2024年5月28日
 *                 修改历史:    2024年5月28日
 *                 函数版本:    1.0
 *
 *****************************************************************************/

static void V(int sem_id, struct sembuf *sops)
{
  sops->sem_op = 1;
  if (semop(sem_id, sops, 1) == -1)
  {
    fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
    exit(1);
  }
}

/*****************************************************************************
 *                 函数名称:     main
 *                 函数功能:    通过对信号量进行PV操作,如果信号量小于0,则阻塞等待,如果大于0,则执行读操作
 *                 函数参数:	  int sem_id, struct sembuf *sops
 *                 返回结果:    NONE
 *                 注意事项:    NONE
 *                 函数作者:    15070884254@163.com
 *                 创建日期:    2024年5月28日
 *                 修改历史:    2024年5月28日
 *                 函数版本:    1.0
 *
 *****************************************************************************/
int main(int argc, char const *argv[])
{
  // 获取信号量id
  int sem_id = semget(ftok(".", 1), 1, 0664);
  if (sem_id == -1) // 获取失败直接退出程序
  {
    fprintf(stderr, "semget error, errno: %d, %s\n", errno, strerror(errno));
    exit(1);
  }

  // 打开共享队列
  int shm_id = shmget(ftok(".", 2), 4, 0664);
  if (shm_id == -1) // 获取失败直接退出程序
  {
    fprintf(stderr, "shmget error, errno: %d, %s\n", errno, strerror(errno));
    exit(1);
  }

  // 获取共享内存的映射地址
  int *shm_ptr = (int *)shmat(shm_id, NULL, 0);

  int i = 0;
  // 设置信号量buf
  struct sembuf sops;
  while (1)
  {
    // 初始化buf
    memset(&sops, 0, sizeof(sops));

    P(sem_id, &sops); // 执行操作前先‘P’一下

    printf("new data: %d\n", *shm_ptr); // 执行读操作

    V(sem_id, &sops); // 执行操作前先‘V’一下
    sleep(3);
  }

  return 0;
}
posted @ 2024-05-28 20:17  罗天天  阅读(7)  评论(0编辑  收藏  举报