首页 > 系统相关 >信号量集与共享内存

信号量集与共享内存

时间:2024-05-28 20:23:00浏览次数:25  
标签:共享内存 errno 信号量 sem include id

信号量集与共享内存

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

​ 1.我们在使用信号量集函数接口前首先得了解其中的结构体,如下

struct sembuf

{

unsigned short sem_num;

short sem_op;

short sem_flg;

}

1.1 semb.sem_num = 0,sem_num成员指的是信号量集中的信号量元素的下标,通过可以访问信号量集中的某个信号量,就相当于可以访问某种公共资源

1.2 semb.sem_op = -1,semb.sem_op成员指的是对选中的信号量的操作,常见的操作就是P/V操作,如果该成员是正整数,则表示释放信号量,相当于完成V操作。如果该成员是负整数则表示申请信号量,相当于完成P操作。如果该成员的值为0时,就称为等零操作,即阻塞等待直到对应的信号量元素的值为零
1.3 semb.sem_flg成员指的是操作的标志位,常见的标志位有IPC_NOWAIT和SEM_UNDO,不设置的话可以为0

​ 2.创建好一个信号量集之后,用户就可以对信号量集中的信号量资源进行PV操作,Linux系统提供了一个名字叫做semop()的函数,用户通过该函数可以实现对信号量进行申请或者释放。

目录

进程A

/*****************************************************************
*
*      file name :main.c
*      authour   :[email protected]
*      date      :2024.05.28 
*      function  :设计一个函数,用于创建一个共享内存以及一个信号量集。
*      note      :为防止重复创建,需要先判断共享内存和信号量集是否存在。
*      CopyRight (c)   2024   [email protected]   All Right Reseverd
*
******************************************************************/
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/msg.h>
#include <features.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.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 main()
{
    // 创建共享内存对象
    int shm_id = shmget(ftok(".",6),512,0644|IPC_CREAT|IPC_EXCL);
    if(-1 == shm_id)
    {
        fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
        shm_id = shmget(ftok(".",6),512,0644);
        if(-1 == shm_id)
        {
            fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
            return -1;
        }
    }
    
    // 映射共享内存
    int *shmmp = (int *)shmat(shm_id,NULL,0);
    if((void *)-1 == shmmp)
    {
        fprintf(stderr,"shmat error,errno:%d,%s\n",errno,strerror(errno));
        return -1;
    }
    *shmmp = 0;
    //创建一个信号集
    int sem_id = semget(ftok(".",6),1,0644|IPC_CREAT);
    if(-1 == sem_id)
    {
        fprintf(stderr,"sem error,errno:%d,%s\n",errno,strerror(errno));
        return -1;
    }
    printf("sem_id = %d\n",sem_id);
    union semun semn;    //定义一个信号量联合体 变量
    semn.val = 1;       //将信号量联合体中的val的值赋值为1
    semctl(sem_id,0,SETVAL,semn);        //通过semctl函数接口将信号量的值设为1
    while(1)
    sleep(1);
    
    return 0;
}

​ Linux系统内核需要对创建成功的信号量集进行维护,所以会记录每个信号量集的属性和信息,Linux系统提供了一个名称叫做semctl()的函数接口,用户可以调用该函数接口来实现设置信号量集的属性、获取信号量集的属性、删除信号量集等操作

进程B

设计一个函数,用于打开一个共享内存以及一个信号量集,并进行p/v操作,每次操作后对共享内存内的值加一,并打印。

/*****************************************************************
*
*      file name :main.c
*      authour   :[email protected]
*      date      :2024.05.28 
*      function  :设计一个函数,用于打开一个共享内存以及一个信号量集,并进行p/v操作,每次操作后对共享内存内的值加一,并打印。
*      note      :为防止重复创建,需要先判断共享内存和信号量集是否存在。
*      CopyRight (c)   2024   [email protected]   All Right Reseverd
*
******************************************************************/

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

/*1.semb.sem_num = 0	sem_num成员指的是信号量集中的信号量元素的下标,
*通过可以访问信号量集中的某个信号量,就相当于可以访问某种公共资源,semb.sem_op = -1
*2.semb.sem_op成员指的是对选中的信号量的操作,常见的操作就是P/V操作,如果该成员是正整数,则表示释放信号量,
*相当于完成V操作。如果该成员是负整数则表示申请信号量,相当于完成P操作。如果该成员的值为0时,就称为等零*
*操作,即阻塞等待直到对应的信号量元素的值为零
*3.semb.sem_flg成员指的是操作的标志位,常见的标志位有IPC_NOWAIT和SEM_UNDO,不设置的话可以为0
*/
int p(int sem_id,int sem_num)
{
    struct sembuf semb = {sem_num,-1,0};   
    semop(sem_id,&semb,1);
}

int v(int sem_id,int sem_num)
{
    struct sembuf semb = {sem_num,1,0};
    semop(sem_id,&semb,1);
}

int main()
{
    // 创建共享内存对象
    int shm_id = shmget(ftok(".",6),512,0644|IPC_CREAT|IPC_EXCL);
    if(-1 == shm_id)
    {
        fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
        shm_id = shmget(ftok(".",6),512,0644);
        if(-1 == shm_id)
        {
            fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
            return -1;
        }
    }

    // 映射共享内存
    int *shmmp = (int *)shmat(shm_id,NULL,0);
    if((void *)-1 == shmmp)
    {
        fprintf(stderr,"shmat error,errno:%d,%s\n",errno,strerror(errno));
        return -1;
    }
    
    int sem_id = semget(ftok(".",6),1,0644|IPC_CREAT);
    if(-1 == sem_id)
    {
        fprintf(stderr,"sem error,errno:%d,%s\n",errno,strerror(errno));
        return -1;
    }
    printf("%d\n",shmmp[0]);

    //对共享内存的操作是先加锁,再解锁,更像是标志位-1为p操作,1是v操作
    while(1)
    {
        //p操作是原子操作无法打断,且当进行p操作时,sembuf结构体中的sem_op成员的值必须为-1
        p(sem_id,0);       
        // (*shmmp) = (*shmmp) + 1; //当p操作时,所以需要先加锁,再进行对共享内存的操作,将共享内存内的值加一

        // printf("%d\n",shmmp[0]);

        //v操作是原子操作无法打断,且当进行v操作时,sembuf结构体中的sem_op成员的值必须为1
        v(sem_id,0);
        (*shmmp) = (*shmmp) + 1;                 //当v操作时,所以需要先解锁,再进行对共享内存的操作,将共享内存内的值加一
        sleep(3);
        printf("%d\n",shmmp[0]);
    }
    
    return 0;
}

进程C

设计一个函数,用于打开一个共享内存以及一个信号量集,并进行p/v操作,每次操作后对共享内存内的值加一,并打印同时观看进程B打印出来的内容观察p/v操作的效果。

/*****************************************************************
*
*      file name :main.c
*      authour   :[email protected]
*      date      :2024.05.28 
*      function  :设计一个函数,用于打开一个共享内存以及一个信号量集,并进行p/v操作,每次操作后对共享内存内的值加一,并打印同时观看semb函数打印出来的内容观察p/v操作的效果。
*      note      :为防止重复创建,需要先判断共享内存和信号量集是否存在。
*      CopyRight (c)   2024   [email protected]   All Right Reseverd
*
******************************************************************/
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/msg.h>
#include <features.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int p(int sem_id,int sem_num)
{
    struct sembuf semb = {sem_num,-1,0};
    semop(sem_id,&semb,1);
}

int v(int sem_id,int sem_num)
{
    struct sembuf semb = {sem_num,1,0};
    semop(sem_id,&semb,1);
}
int main()
{
    char num[100];
    // 创建共享内存对象
    int shm_id = shmget(ftok(".",6),512,0644|IPC_CREAT|IPC_EXCL);
    if(-1 == shm_id)
    {
        fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
        shm_id = shmget(ftok(".",6),512,0644);
        if(-1 == shm_id)
        {
            fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
            return -1;
        }
    }

    // 映射共享内存
    int *shmmp = (int *)shmat(shm_id,NULL,0);
    if((void *)-1 == shmmp)
    {
        fprintf(stderr,"shmat error,errno:%d,%s\n",errno,strerror(errno));
        return -1;
    }
    
    int sem_id = semget(ftok(".",6),1,0644|IPC_CREAT);
    if(-1 == sem_id)
    {
        fprintf(stderr,"sem error,errno:%d,%s\n",errno,strerror(errno));
        return -1;
    }

    while(1)
    {
        //p操作是原子操作无法打断,且当进行p操作时,sembuf结构体中的sem_op成员的值必须为-1
        p(sem_id,0);       
        // (*shmmp) = (*shmmp) + 1;                //当p操作时,所以需要先加锁,再进行对共享内存的操作,将共享内存内的值加一
        // printf("%d\n",shmmp[0]);

        //v操作是原子操作无法打断,且当进行v操作时,sembuf结构体中的sem_op成员的值必须为1
        v(sem_id,0);
        (*shmmp) = (*shmmp) + 1;                 //当v操作时,所以需要先解锁,再进行对共享内存的操作,将共享内存内的值减一
        sleep(3);

        printf("%d\n",shmmp[0]);
    }

    return 0;
}

标签:共享内存,errno,信号量,sem,include,id
From: https://www.cnblogs.com/xiaobaibudongjiuwen/p/18218779

相关文章

  • A申请共享内存并对信号量进行初始化,然后进程B与C实现互斥
    练习:设计一个程序,作为进程A,进程A专门创建一个信号量集,要求信号量集中有1个信号量,对信号量集合中的信号量进行设置,要求集合中的信号量的初值为1,然后再设计2个程序,分别是进程B和进程C,要求进程B和进程C使用进程A创建的信号量集合中的信号量实现互斥访问。提示:进程A、进程B、进......
  • 共享内存练习题
    设计三个程序,要求三个程序申请一块共享内存,并分别映射到各自进程的地址空间,进程A和进程B对共享内存段中的数据进行修改,然后进程C不断输出共享内存段中的数据,并观察效果,要求实现进程间的互斥,避免竞争。进程A:/******************************************************************......
  • 【.NET深呼吸】线程信号量(Semaphore)
    Semaphore类可以控制某个资源允许访问的线程数,Semaphore有命名式的,也有不命名的;如果不考虑跨进程工作,一般在代码中使用不命名方式即可。信号量有点类似于等待句柄,某个线程如果调用了WaitOne方法,这个线程就会暂停,并且等待有可用的信号量时才会继续执行;某个线程调用Release方法,就......
  • 《安富莱嵌入式周报》第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)工作原理:内存映射是将文件的一部分映射到进程的地址空间中,使得文件内容可以直接被读写,就像操作内存一样。特点:文件内容可以通......
  • JVM非运行时共享内存之直接内存
    直接内存(DirectMemory)并不是虚拟机运行时数据区的一部分。为何存在呢?观察下两图进行对比:有没有似曾相识?!很多架构的设计都基于这种思想,提高性能和效率。NIO的Buffer提供一个可以直接访问系统物......
  • golang进程通过共享内存和C++进程进行通信
    目录serverclientserverC++可以使用POSIX共享内存API来创建和管理共享内存server.cpp#include<fcntl.h>#include<sys/mman.h>#include<sys/stat.h>#include<unistd.h>#include<cstring>#include<iostream>constchar*S......
  • 信号量
    3个信号量,就是停车场的3个入口,作用:限流,可以最多3辆车一起并发,进入停车场,限制并发量;信号量(Semaphore)是一个用于提供不同进程之间或不同线程之间的同步手段的原语。它常被用作锁(Lock)以保护对共享资源的访问,避免发生并发冲突。信号量可以被视为一个计数器,用于控制对多个线程......
  • linux 进程通信之信号量
    信号量Linux函数semget();semctl();semop();信号量三个函数头文件#include<sys/sem.h>intsemget(key_t_key,int_nsems,int_semflg);intsemctl(int_semid,int_semnum,int_cmd……);intsemop(intsemid,structsembuf*_sops,size_t_nsops);se......
  • 信号量 semaphore的实现 -06
    1 semaphore的内核结构体注意:这是信号量,不是信号。在前面学习异步通知时,驱动程序给应用程序发信号。现在我们讲的信号量是一种同步、互斥机制。信号量的定义及操作函数都在Linux内核文件include\linux\semaphore.h中定义,如下: 初始化semaphore之后,就可以使用down函数或其他衍......