首页 > 系统相关 >linux 信号量sem 使用示例

linux 信号量sem 使用示例

时间:2024-07-23 21:30:47浏览次数:14  
标签:示例 int printf 信号量 semaphore sem id

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

提示:这里可以添加本文要记录的大概内容:

信号量主要用于进程间使用
信号量:分为 posix 和 systemV 信号量
posix信号量:

sem_open :打开/创建sem
sem_close :关闭sem
sem_unlink :删除sme
sem_post : P操作+1
sem_wait : V操作 -1,函数小于0的时候会阻塞
sem_getvalue :调试使用,存在竞争态,不使用

systemV信号量:

int semget(key_t key, int nsems, int semflg); * 功能:创建或访问一个信号量集。
int semop(int semid, struct sembuf sops, size_t nsops); * 功能:对信号量集执行操作,如增加或减少信号量的值。
int semctl(int semid, int semnum, int cmd, … /
union semun arg */); * 功能:对信号量集执行控制操作,如初始化信号量、获取信号量信息或删除信号量集。
key_t ftok(const char *pathname, int proj_id); * 功能:用于生成一个唯一键值,用于semget()函数中创建或访问信号量集。


提示:以下是本篇文章正文内容,下面案例可供参考

一、信号量是什么?

信号量(Semaphore)是进程间通信(IPC,Inter-Process Communication)机制的一种,主要用于解决进程间的同步和互斥问题。信号量最早由荷兰计算机科学家 Edsger Dijkstra 提出,它是一种软件抽象,可以控制对共享资源的访问,防止多个进程或线程同时访问同一资源,从而避免竞态条件和死锁。

信号量的基本概念包括:

计数器:信号量本质上是一个计数器,用来记录可用资源的数量。计数器的值可以是正数、零或负数。
P操作(Wait操作):当一个进程想要访问共享资源时,它会对信号量执行 P 操作。P 操作会将信号量的值减1。如果信号量的值大于等于0,则进程可以继续执行并访问资源。如果信号量的值小于0,这意味着没有可用资源,进程会被阻塞,直到资源可用。
V操作(Signal操作):当一个进程完成对资源的使用时,它会对信号量执行 V 操作。V 操作会将信号量的值加1。如果在信号量的等待队列中有被阻塞的进程,其中一个会被唤醒,以访问资源。

二、代码示例

1.posix

代码如下(示例):
代码示例:父进程每3秒生产,子进程每1秒消费,生产不足时候子进程阻塞。
gcc posix_sem.c -o posix_sem -lrt -lpthread -g

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/wait.h>

#define SEMAPHORE_PATH "/example_semaphore"

sem_t* init_semaphore(const char* name) {
    int val = 0;
    sem_t* semaphore = sem_open(name, O_CREAT | O_EXCL, 0644, 1); // 信号量创建时值就为1
    if (semaphore == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    }
    printf("sem_open val = %d\n", val);
    return semaphore;
}


void cleanup_semaphore(sem_t* semaphore) {
    if (sem_close(semaphore) == -1) {
        perror("sem_close");
        exit(EXIT_FAILURE);
    }
    if (sem_unlink(SEMAPHORE_PATH) == -1) {
        perror("sem_unlink");
        exit(EXIT_FAILURE);
    }
}


void increment_semaphore(sem_t* semaphore) {
    if (sem_post(semaphore) == -1) {
        perror("sem_post");
        exit(EXIT_FAILURE);
    }
}

void decrement_semaphore(sem_t* semaphore) {
    if (sem_wait(semaphore) == -1) {
        perror("sem_wait");
        exit(EXIT_FAILURE);
    }
}

int main() {
    sem_t* semaphore = init_semaphore(SEMAPHORE_PATH);
    
    printf("semaphore = %d\n", semaphore);
    
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    } else if (pid > 0) { // 父进程 - 生产者
        int status;
    
        for (int i = 0; i < 5; ++i) {
            printf("Producer incremented semaphore.\n");
            increment_semaphore(semaphore);
            sleep(3);
        }
        pid_t child_pid = waitpid(pid, &status, 0);
        
        cleanup_semaphore(semaphore);
    } else { // 子进程 - 消费者
        int val = 0;
        for (int i = 0; i < 5; ++i) {
            printf("Consumer decremented semaphore.\n");
            decrement_semaphore(semaphore);
            sem_getvalue(semaphore,&val);
            printf("val = %d\n", val);
            sleep(1);
        }
    }

    return 0;
}

2.systemV

代码示例:生产者生产 0 1 sem,消费进程 cust 消费0,cust1 消费 1
要特别注意//op.sem_flg = SEM_UNDO; // 如果设置了SEM_UNDO标志,当线程结束时,系统会自动执行一个V操作(即sem_post),以恢复信号量的初始状态。producer先退出时候会导致consumer1异常, SEM_UNDO是系统推荐设置,尽量设置

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>


void producer(int sem_id);
void consumer(int sem_id);
void consumer1(int sem_id);


union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

int main() {
    int sem_id;
    union semun arg;
    arg.val = 1; // 初始化信号量为1

    key_t key = ftok("/tmp/semaphore_key", 65);
    if (key == (key_t)-1) {  
        perror("ftok failed");
        exit(-1);
    }

/*
    // 创建一个信号量组,有两个信号量
    if ((sem_id = semget(key, 2, 0666 | IPC_CREAT)) == -1) {
        perror("semget");
        exit(1);
    }

    semctl(sem_id, 0, IPC_RMID, 0); // 删除信号量集
    sleep(2);
*/
    //重新创建
    if ((sem_id = semget(/*key*/ 432, 2, 0666 | IPC_CREAT)) == -1) {
        perror("semget");
        exit(1);
    }
    //初始化 0 sem值为1
    if (semctl(sem_id, 0, SETVAL, arg) == -1) {
        perror("semctl");
        exit(1);
    }
    //初始化 1 sem值为1
    if (semctl(sem_id, 1, SETVAL, arg) == -1) {
        perror("semctl");
        exit(1);
    }

    pid_t pid;

    if ((pid = fork()) == 0) { // 子进程1作为消费者
        printf("consumer start\n");
        int i = 5;
        while(i)
        {
            printf("consumer enter i = %d\n", i);
            consumer(sem_id);
            i--;
        }
        printf("consumer end\n");
    } else if ((pid = fork()) == 0) { // 子进程2作为生产者
        int i = 4; 
        while(i)
        {
            printf("producer start i = %d\n", i);
            producer(sem_id);
            i--;
        }
        printf("producer end\n");
        //sleep(10);
    } else if ((pid = fork()) == 0) { // 子进程3作为消费者
        printf("consumer1 start\n");
        int i = 5;
        while(i)
        {
            printf("consumer1 enter i = %d\n", i);
            consumer1(sem_id);
            i--;
        }
        printf("consumer1 end\n");
    }else {
        wait(NULL); // 父进程等待子进程完成
        wait(NULL);
        wait(NULL);
        semctl(sem_id, 0, IPC_RMID, 0); // 删除信号量集
        printf("Semaphore removed.\n");
    }
    
    return 0;
}

void consumer(int sem_id) {
    int ret = -1;
    struct sembuf op;
    op.sem_num = 0;
    op.sem_op = -1; // 减少信号量的值
    op.sem_flg = SEM_UNDO;
    union semun arg;

    while (ret != 0) {
    if (semctl(sem_id, 0, GETVAL, arg) == -1) {
          perror("semctl GETVAL");
          return;
        }

        //printf("consumer Semaphore value is %d\n", arg.val);
        ret = semop(sem_id, &op, 1);
        if (ret == -1) {
            perror("semop");
            exit(1);
        }
        //printf("Consumer decremented semaphore value.\n");
        sleep(2);
    }
}


void consumer1(int sem_id) {
    int ret = -1;
    struct sembuf op;
    op.sem_num = 1;
    op.sem_op = -1; // 减少信号量的值
    op.sem_flg = SEM_UNDO;
    union semun arg;

    while (ret != 0) {
        if (semctl(sem_id, 1, GETVAL, arg) == -1) {
          perror("semctl GETVAL");
          return;
        }

        //printf("consumer1 Semaphore value is %d\n", arg.val);
    
        ret = semop(sem_id, &op, 1);
        if (ret == -1) {
            perror("semop");
            exit(1);
        }
        //printf("Consumer1 decremented semaphore value.\n");
        sleep(3);
    }
}


void producer(int sem_id) {
    int ret = -1;
    struct sembuf op;
    struct sembuf op1;
    op.sem_num = 0;
    op.sem_op = 1; // 增加信号量的值
    //op.sem_flg = SEM_UNDO; // 如果设置了SEM_UNDO标志,当线程结束时,系统会自动执行一个V操作(即sem_post),以恢复信号量的初始状态。producer先退出时候会导致consumer1异常,系统推荐设置
    union semun arg;

    while (ret != 0) {
        ret = semop(sem_id, &op, 1);
        if (ret == -1) {
            perror("semop");
            exit(1);
        }
        printf("Producer incremented semaphore 0 value.\n");
        if (semctl(sem_id, 0, GETVAL, arg) == -1) {
          perror("semctl GETVAL");
          return;
        }

        //printf("producer Semaphore value 0 is %d\n", arg.val);
        sleep(1);
    }

    ret = -1;
    op1.sem_num = 1;
    op1.sem_op = 1; // 增加信号量的值
    //op1.sem_flg = SEM_UNDO;

    while (ret != 0) {
        ret = semop(sem_id, &op1, 1);
        if (ret == -1) {
            perror("semop");
            exit(1);
        }
        printf("Producer incremented semaphore 1 value.\n");
        if (semctl(sem_id, 1, GETVAL, arg) == -1) {
          perror("semctl GETVAL");
          return;
        }

        //printf("producer Semaphore value 1 is %d\n", arg.val);
        sleep(1);
    }
}


总结

linux下 posix 和 systemV 信号量代码示例,可以运行

标签:示例,int,printf,信号量,semaphore,sem,id
From: https://blog.csdn.net/qq_37077309/article/details/140613325

相关文章

  • MBR60200PT-ASEMI无人机专用MBR60200PT
    编辑:llMBR60200PT-ASEMI无人机专用MBR60200PT型号:MBR60200PT品牌:ASEMI封装:TO-247批号:最新恢复时间:35ns最大平均正向电流(IF):60A最大循环峰值反向电压(VRRM):200V最大正向电压(VF):0.85V~0.90V工作温度:-40°C~175°C芯片个数:2芯片尺寸:mil正向浪涌电流(IFMS):500AMBR60200PT特性:......
  • S75VB120-ASEMI光伏专用模块S75VB120
    编辑:llS75VB120-ASEMI光伏专用模块S75VB120型号:S75VB120品牌:ASEMI封装:SVB-4批号:2024+现货:50000+正向电流(Id):75A反向耐压(VRRM):1200V正向浪涌电流:500A正向电压(VF):1.10V引脚数量:4芯片个数:4芯片尺寸:102MIL功率(Pd):大功率工作温度:-55°C~150°C类型:整流方桥、插件整流桥......
  • 超热门!身份证实名认证接口Java调用示例
    一、什么是身份证实名认证?输入姓名、身份证号,校验此两项是否匹配,同时返回生日、性别、籍贯等信息。二、身份证实名认证接口适用哪些场景呢?金融领域、电商与支付、社交与通讯、交通与出行、在线教育与培训等。三、如何用Java快速调用该接口呢?以下以阿里云为例:接口地址:身份......
  • Apache压测工具ab(Apache Bench)工具的下载安装和使用示例
    场景Jmeter进行http接口压力测试:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/124928498上面讲压测工具Jmeter的使用,下面介绍另外一个ab(ApacheBench)压测工具的使用。apachebenchapachebench是apache自带的压力测试工具。ab不仅可以对apache服务器进行网......
  • ValueError:信号量或锁释放次数过多?
    当我尝试在Cygwin中执行操作时,我会得到ValueError:semaphoreorlockreleasedtoomanytimes我该怎么办?pipinstallmatplotlib更新:UPDATE:$pipinstallmatplotlibDownloading/unpackingmatplotlibYouareinstallinganexternallyhosted......
  • 纳米体育数据API电竞数据接口:指数数据包接口文档API示例①
    纳米体育数据的数据接口通过JSON拉流方式获取200多个国家的体育赛事实时数据或历史数据的编程接口,无请求次数限制,可按需购买,接口稳定高效;覆盖项目包括足球、篮球、网球、电子竞技、奥运等专题、数据内容。纳米数据API2.0版本包含http协议以及websocket协议,主要通过http获取数......
  • TFHE库示例代码
    默认已经成功安装TFHE库,如果没安装可以看前面的文章本节使用TFHE中的示例代码代码位置tfhe/src/test/test-lwe.cpp,代码引入库时做了修改:#include<stdio.h>#include<iostream>#include<iomanip>#include<cstdlib>#include<cmath>#include<sys/time.h>#incl......
  • 嵌入式C++、FreeRTOS、MySQL、Spring Boot和MQTT协议:智能零售系统详细流程介绍(代码示
    项目概述随着科技的发展,零售行业正经历着一场数字化转型。智能零售系统通过集成嵌入式技术和大数据分析,为商家提供了高效的运营管理工具。该系统的核心目标是提升顾客体验、优化库存管理、降低运营成本以及实现精准营销。本项目将结合多种技术栈,包括嵌入式硬件、嵌入式软件、......
  • 嵌入式C++、STM32F103、MQTT、InfluxDB存储和Grafana可视化:工厂设备的实时监控和数据
    1.项目概述随着工业4.0的推进,智能制造已成为制造业发展的必然趋势。本文介绍了一套基于STM32和MQTT协议的小型工厂设备监控系统,可实现对工厂设备的实时监控和数据分析,有效提高生产效率和安全性。系统主要包括三个部分:设备端:使用STM32MCU连接各种传感器,采集设备运行......
  • 嵌入式C++、InfluxDB、Spark、MQTT协议、和Dash:树莓派集群物联网数据中心设计与实现(代
    1.项目概述随着物联网技术的快速发展,如何高效地收集、存储和分析海量IoT设备数据成为一个重要课题。本文介绍了一个基于树莓派集群搭建的小型物联网数据中心,实现了从数据采集到分析可视化的完整流程。该系统采用轻量级组件,适合资源受限的边缘计算环境。主要功能包括:通......