2-16 信号量互斥编程

本文深入讲解了信号量的基本概念及分类,并详细介绍了信号量相关的三个核心函数:semget、semop 和 semctl 的使用方法。通过一个综合实例展示了如何利用信号量实现进程间的数据互斥访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(本节笔记的实验代码,在这里


1.  信号量

    1.1  基本概念:主要用于保护临界资源(进程互斥),进程可以根据此判定是否能够访问某些共享资源。除了用于访问控制以外,还可用于进程间的同步。

    1.2  分类:第一种是二值信号,只能取0或1;第二种是计算信号量,可取任意非负值。


2.  函数学习

    2.1  创建信号量集合

        函数名:

                semget

        函数原型:

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

        函数功能:

                获取信号量的标识符,若key指定的信号量集合不存在,若semflg里包含了IPC_CREAT,则创建一个信号量集合。

        所属头文件:

                <sys/types.h>    <sys/ipc.h>    <sys/sem.h>

        返回值:

                成功:返回信号量集合的标识符    失败:返回-1

        参数说明:

                key:“键值”,一个数字,相当于文件的pathname,ipc对象都有一个键值

                构造方法:key_t ftok (char *fname, int id);

fname文件名  ——>对应的数字——>    

                                       项目ID     ——>    由对应数字和项目ID得出key

                nsems:创建的信号量集合所包含的信号量数目

                semflg:IPC_CREAT,若信号量集合不存在,则创建,信号量的数目由nsems指定


    2.2  操作信号量集合

        函数名:

                semop

        函数原型:

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

        函数功能:

                操作信号量

        所属头文件:

                <sys/types.h>    <sys/ipc.h>    <sys/sem.h>

        返回值:

                成功:返回0    失败:返回-1

        参数说明:

                semid:要操作的信号量集合的标识符

                sops:是一个struct的地址

                        struct sembuf{

                                unsigned short sem_num    /*  需要操作的信号量的号码  */

                                short sem_op    /*  对信号量的操作,正数为释放,负数为获取,获取失败会导致进程等待  */

                                short sem_flg    /*  操作的标志    SEM_UNDO  */

                        }  

                nsops:要操作多少个信号量


    2.3  操作信号量

        函数名:

                semctl

        函数原型:

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

        函数功能:

                对信号量的操作,如查看或者设置信号量的值等。

        所属头文件:

                <sys/sem.h>

        返回值:

                根据各cmd的不同而有所不同

        参数说明:

                semid:要操作的信号量集合的标识符

                semnum:要操作的信号量的号码

                cmd:操作的方式,如:

                        SETVAL:设定semnum的semval值

                        GETVAL:获取semnum的semval值

                参数4:要设定的值


3.  综合实例

/*  有这么的设定  */

/******************************************************************************

在一个文件中,进程A写入“aaaaa”,然后sleep(10),再写入“bbbbb”,

进程B对同一个文件写入“ccccc”,利用互斥信号量,是的B在A写完后再写

******************************************************************************/


/*  touch a_student.c  */

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/ipc.h>

#include <sys/sem.h>

#include <unistd.h>


int main(int argc, char ** argv)

{

    int val_sem;
    int fd_sem;
    int semnum_sem;
    key_t key_sem;
    struct sembuf buf_sem;
    
    fd_sem = open("./sem.txt",O_RDWR | O_APPEND | O_CREAT, 0777);
    printf("fd_sem val is %d\n",fd_sem);


    key_sem = ftok("/arm/key_sem", 1);
    printf("key_sem val is %d\n",key_sem);


    semnum_sem = semget(key_sem, 1, IPC_CREAT);
    printf("semnum_sem val is %d\n",semnum_sem);


    val_sem = semctl(semnum_sem, 0, GETVAL);
    printf("a val is %d\n", val_sem);


    semctl(semnum_sem, 0, SETVAL, 1);
    val_sem = semctl(semnum_sem, 0, GETVAL);
    printf("a val is %d\n", val_sem);
    
    buf_sem.sem_num = 0;
    buf_sem.sem_op = -1;
    semop(semnum_sem, &buf_sem, 1);

    write(fd_sem,"aaaaa",5);

    sleep(10);

    write(fd_sem,"bbbbb",5);

    buf_sem.sem_num = 0;
    buf_sem.sem_op = 1;
    semop(semnum_sem, &buf_sem, 1);

    close(fd_sem);

    return 0;

}


/*  touch b_student.c  */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>

int main()
{
    int val_sem;
    int fd_sem;
    int semnum_sem;
    key_t key_sem;
    struct sembuf buf_sem;

    fd_sem = open("./sem.txt",O_RDWR | O_APPEND | O_CREAT, 0777);
    printf("fd_sem val is %d\n",fd_sem);

    key_sem = ftok("/arm/key_sem", 1);
    printf("key_sem val is %d\n",key_sem);

    semnum_sem = semget(key_sem, 1, IPC_CREAT);
    printf("semnum_sem val is %d\n",semnum_sem);
    
    val_sem = semctl(semnum_sem, 0, GETVAL);
    printf("B val is %d\n", val_sem);

    buf_sem.sem_num = 0;
    buf_sem.sem_op = -1;
    semop(semnum_sem, &buf_sem, 1);

    write(fd_sem,"ccccc",5);

    buf_sem.sem_num = 0;
    buf_sem.sem_op = 1;
    semop(semnum_sem, &buf_sem, 1);

    close(fd_sem);

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值