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

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

时间:2024-05-28 20:22:40浏览次数:16  
标签:sops include int errno 信号量 互斥 sem 共享内存 id

练习:设计一个程序,作为进程 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:         [email protected] 
*          date:            2024年5月27日
*          function:        新建一个共享内存,并初始化为0。

*          note:          假定sleep模拟的是程序的运行时间。如 果在A或者B的sleep时间内,终止运行,会导致B或者C未能进行V操作,导致B和C都不能再次进行。此时需要重新执行A进程来对内存空间里面的数据初始化
*
*        CopyRight (c)      [email protected]      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
*                 函数作者:    [email protected] 
*                 创建日期:    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
*                 函数作者:    [email protected] 
*                 创建日期:    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
*                 函数作者:    [email protected] 
*                 创建日期:    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
*                 函数作者:    [email protected] 
*                 创建日期:    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
 *                 函数作者:    [email protected]
 *                 创建日期:    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
 *                 函数作者:    [email protected]
 *                 创建日期:    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
 *                 函数作者:    [email protected]
 *                 创建日期:    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;
}

标签:sops,include,int,errno,信号量,互斥,sem,共享内存,id
From: https://www.cnblogs.com/luo-tt/p/18218775

相关文章

  • 利用信息量集实现互斥访问
    进程A用来生成信号集,并将其初值设为1(运行顺序为进程A->B->C)/**@Author:[email protected]*@Date:2024-05-0817:20:41*@LastEditors:[email protected]*@LastEditTime:2024-05-2818:47:38*/#include<stdio.h>#include<stdlib.h>#include<sys/......
  • 进程间同步(互斥锁)
    【一】什么是互斥锁互斥锁是一种用于多线程编程中控制对共享资源访问的机制限制当前时间段只能由当前进程使用,当前进程使用完成后才能其他进程继续使用基本原理是在对共享资源进行访问前加锁,使得其他线程无法访问该资源,当访问完成后再解锁,使得其他线程可以进行访问【......
  • 共享内存练习题
    设计三个程序,要求三个程序申请一块共享内存,并分别映射到各自进程的地址空间,进程A和进程B对共享内存段中的数据进行修改,然后进程C不断输出共享内存段中的数据,并观察效果,要求实现进程间的互斥,避免竞争。进程A:/******************************************************************......
  • 【.NET深呼吸】线程信号量(Semaphore)
    Semaphore类可以控制某个资源允许访问的线程数,Semaphore有命名式的,也有不命名的;如果不考虑跨进程工作,一般在代码中使用不命名方式即可。信号量有点类似于等待句柄,某个线程如果调用了WaitOne方法,这个线程就会暂停,并且等待有可用的信号量时才会继续执行;某个线程调用Release方法,就......
  • 互斥锁、进程间通信(IPC)、队列(queue)模块、队列实现进程间通信、生产者和消费者模型
    【一】互斥锁【1】什么是进程同步(互斥锁)互斥锁(Mutex)是一种用于多线程编程中控制对共享资源访问的机制。其作用是保证在同一时刻只有一个线程在访问共享资源,从而避免多个线程同时读写数据造成的问题。互斥锁的基本原理是在对共享资源进行访问前加锁,使得其他线程无法访问该......
  • 互斥锁、自旋锁、读写锁、悲观锁和乐观锁
    都有哪些锁?互斥锁、自旋锁、读写锁、乐观锁、悲观锁。互斥锁与自旋锁加锁的目的就是保证共享资源在任意时间里,只有一个线程访问,这样就可以避免多线程导致共享数据错乱的问题。当已经有一个线程加锁后,其他线程加锁则就会失败,互斥锁和自旋锁对于加锁失败后的处理方式是不......
  • 线程互斥锁
    所有子线程都会进行阻塞操作,导致最后的改变只是改了一次fromthreadingimportThreadimporttimemoney=100deftask():globalmoney#模拟获取到车票信息temp=money#模拟网络延迟time.sleep(2)#模拟购票money=temp-1defmain():task_list=[Thread(ta......
  • 27.并发编制【四】互斥锁与队列
    【一】互斥锁(进程间同步)1)概念一种用于多线程编程中控制对方共享资源访问机制为当前进程或线程添加额外的限制,限制当前时间段只能由当前进程使用,当前进程使用完成后才能其他进程继续使用其可保证同一时间只有一个进程在执行关键代码段,从而保证了数据的安全性2)多个进程......
  • 《安富莱嵌入式周报》第337期:超高性能信号量测量,协议分析的开源工具且核心算法开源,工
    周报汇总地址:http://www.armbbs.cn/forum.php?mod=forumdisplay&fid=12&filter=typeid&typeid=104 视频版:https://www.bilibili.com/video/BV1PT421S7TR/目录1、一款超高性能信号量测量,协议分析的开源跨平台上位机工具ngscopeclient,核心算法全开源2、ST推出面向工业安全......
  • 内存映射和共享内存的区别
    内存映射(MemoryMapping)和共享内存(SharedMemory)都是在进程间进行内存共享的机制,但它们在工作原理和使用方式上有一些区别。内存映射(MemoryMapping)工作原理:内存映射是将文件的一部分映射到进程的地址空间中,使得文件内容可以直接被读写,就像操作内存一样。特点:文件内容可以通......