Linux操作系统 使用信号量实现进程同步

信号量

不加入控制模拟使用打印机:

比如:进程a和进程b模拟访问打印机,进程a输出第一个字符'a' 表示开始使用打印机,输出第二个字符'a'表示结束使用,b进程操作与a进程相同。

复制代码
//a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
int main()
{
    int i=0;
    for(;i<5;i++)
    {
        printf("A");
        fflush(stdout);
        int n=rand()%3;
        sleep(n);
        printf("A");
        fflush(stdout);
        n=rand()%3;
        sleep(n);
    }
}

//b.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
int main()
{
    int i=0;
    for(;i<5;i++)
    {
        printf("B");
        fflush(stdout);
        int n=rand()%3;
        sleep(n);
        printf("B");
        fflush(stdout);
        n=rand()%3;
        sleep(n);
    }
}

正确的结果应该是:AABB成对出现

但由于打印机同一时刻只能被一个进程使用,所以输出结果不应该出现ABAB这样的交替结果

所以上面代码得到的结果是错误的

信号量的介绍

信号量就是控制某个进程能够对某个资源进行访问;保证同一时刻只能由一个进程对某个资源进程访问;

信号量是一个特殊的变量,对信号量的操作都是一个原子操作;

打印机

信号量就是一个特殊的变量,一般为正整数。他的值代表允许访问的资源树木,获取资源的时候,需要对信号量的值进行原子-1,该操作被称作P操作。当信号量的值为0的时候,代表没有资源可用,P操作会被阻塞。释放资源时,需要对信号量的值进行原子+1,该操作被称作V操作。信号量主要用来同步进程。信号量的值如果只取0,1,将其称为二值信号量。如果信号量的值大于1,则称之为技术信号量。

临界资源:同一时刻,只能允许被一个进程或者线程访问的资源;

临界区:访问临界资源的代码段;

信号量接口介绍

复制代码
(1)semget

int  semget(key_t  key,int nsems,int semflg);

创建或者获取一个已经存在的信号量;

key:两个进程使用相同的key值,就可以使用同一个信号量;

nsems:创建几个信号量;

semflg:标志位;如果为创建:IPC_CREAT;

如果为全新创建,也就是不知道是否有人创建过,则IPC_CREAT|IPC_EXCL,
就是如果没有则创建,如果有则创建失败 ;

(2)semop:

int semop(int semid,struct sembuf *sops,unsigned nsops);  

对信号量进行改变,做P操作或者V操作;

semid:信号量的id号,也就是刚才semget的返回值;说明对哪个信号量进行操作;
sops:结构体指针,指向sembuf的结构体指针,
sembuf结构体有三个成员变量:
sem_num表示信号量的编号(即指定信号量集中的信号量下标);
sem_op表示是p还是v操作;1为v操作(加1),-1为p操作(减1);
sem_flg为标志位;  



(3)semctl:

int semctl(int semid,int semnum,int cmd,...);  

对信号量进行控制:初始化/删除信号量

semid:信号量id;

semnum:信号量编号;

cmd:命令:SETVAL:初始化信号量;      IPC_RMID:删除信号量;

**注意**:联合体semun,这个联合体需要自己定义;

有控制的使用打印机(信号量控制):

复制代码
//sem.h
#include <sys/sem.h>
#include <unistd.h>
#include <stdio.h>

union semun{
    int val;
};

void sem_init();
void sem_p();
void sem_v();
void sem_destroy();


//sem.c
#include "sem.h"

static int semid=-1;

void sem_init()
{
   semid=semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);
   if(semid==-1)
   {
       semid=semget((key_t)1234,1,0600);
       if(semid==-1)
       {
           perror("semget error!\n");
       }
   }
   else
   {
       union semun  a;
       a.val=1;
       if(semctl(semid,0,SETVAL,a)==-1)
       {
           perror("semctl init error!");
       }
   }
}


void sem_p()
{
    struct sembuf buf;
    buf.sem_num=0;
    buf.sem_op=-1;
    buf.sem_flg=SEM_UNDO;
    if(semop(semid,&buf,1)==-1)
    {
        perror("p error!\n");
    }
}

void sem_v()
{
    struct sembuf buf;
    buf.sem_num=0;
    buf.sem_op=1;
    buf.sem_flg=SEM_UNDO;
    if(semop(semid,&buf,1)==-1)
    {
        perror("v error!\n");
    }
}

void sem_destroy()
{
    if(semctl(semid,0,IPC_RMID)==-1)
    {
        perror("destroy sem error!\n");
    }
}

//a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include "sem.h"
int main()
{
    int i=0;
    sem_init();
    for(;i<5;i++)
    {
        sem_p();
        printf("A");
        fflush(stdout);
        int n=rand()%3;
        sleep(n);
        printf("A");
        fflush(stdout);
        sem_v();
        n=rand()%3;
        sleep(n);
    }

    sleep(10);
    sem_destroy();
}

//b.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include "sem.h"
int main()
{
    int i=0;
    sem_init();
    for(;i<5;i++)
    {   
        sem_p();
        printf("B");
        fflush(stdout);
        int n=rand()%3;
        sleep(n);
        printf("B");
        fflush(stdout);
        sem_v();
        n=rand()%3;
        sleep(n);
    }   
}

相关推荐
守城小轩2 小时前
基于Chrome140的Quora账号自动化(关键词浏览)——运行脚本(三)
运维·自动化·chrome devtools·指纹浏览器·浏览器开发
未来之窗软件服务2 小时前
幽冥大陆(五十五)ASR SetThreadInformation C语言识别到自动化软件
运维·自动化·asr·东方仙盟·操作系统级别错误
开开心心就好2 小时前
免费卸载工具,可清理残留批量管理启动项
linux·运维·服务器·windows·随机森林·pdf·1024程序员节
陈陈爱java2 小时前
RRT建模
算法
智算菩萨2 小时前
摩擦电纳米发电机近期进展的理论脉络梳理:从接触起电到统一建模与能量转换
linux·人工智能·算法
xiaolang_8616_wjl2 小时前
c++超级细致的基本框架
开发语言·数据结构·c++·算法
Lbwnb丶2 小时前
检测服务器是否是虚拟化,如KVM,VM等
linux·运维·服务器
老猿讲编程2 小时前
【车载信息安全系列4】基于Linux中UIO的HSE应用实现
linux·运维·服务器
鸡吃丸子2 小时前
初识Docker
运维·前端·docker·容器
艾醒2 小时前
大模型原理剖析——拆解预训练、微调、奖励建模与强化学习四阶段(以ChatGPT构建流程为例)
算法