linux多进程基础(8):信号量(sem_open(), sem_close(),sem_wait(),sem_post(), sem_unlink()函数)

本文详细介绍了Linux多进程中如何使用信号量解决共享内存数据安全问题,包括sem_open(),sem_close(),sem_wait(),sem_post(),sem_unlink()等函数的使用示例,以及一个实际例子展示了如何通过信号量实现父子进程间对共享内存的同步操作。
摘要由CSDN通过智能技术生成

在Linux多进程编程的章节(7)中,我们深入探讨了共享进程资源的重要性。尽管这显著提高了系统的执行效率,但也带来了一些挑战。当多个进程同时读写共享内存时,数据安全性问题便浮出水面。正是为了解决这些问题,我们需要引入信号量的概念。

1.什么是信号量

信号量是多进程环境中使用的一种方法,用于实现进程间的互斥与同步,以保证它们能够正确、合理地使用公共资源。信号量是一个计数器,用于控制多个进程对共享资源的访问。常用的信号量函数包括:sem_open(), sem_close(),sem_wait(),sem_post(), sem_unlink(),将逐一进行介绍.

2.sem_open()

 sem_open() 用于打开或创建一个命名信号量,其定义如下:

sem_t *sem_open(const char *name, int oflag, ...);

其中,name代表信号量的名字;oflag为打开标志,常用的有 O_CREATO_EXCLO_CREAT 表示如果名字的信号量不存在则创建它,而 O_EXCL 则在创建新信号量时使用,如果名字的信号量已经存在则返回错误。...代表当使用 O_CREAT 标志时,用于指定信号量初始值的参数。如果没有使用 O_CREAT,则此参数被忽略。

若函数执行成功,则返回一个指向信号量的指针;如果失败,返回 SEM_FAILED

3. sem_close()

 sem_close()用于关闭已打开的信号量,其定义如下:

int sem_close(sem_t *sem);

其中,sem为指向已打开的信号量的指针。

若函数执行成功,返回 0,失败返回-1。

4.sem_wait()

 sem_wait() 用于等待信号量,它会使调用进程等待,直到信号量的值大于零。其定义如下:

int sem_wait(sem_t *sem);

其中,sem为指向信号量的指针。

若函数执行成功,返回 0,失败返回-1。

5.sem_post()

 sem_post()用于当一个进程完成对共享资源的访问后释放信号量,这样其他等待该信号量的进程就可以继续执行。其定义如下:

int sem_post(sem_t *sem);

其中,sem为指向信号量的指针。

若函数执行成功,返回 0,失败返回-1。

6.sem_unlink()

sem_unlink() 用于当一个命名信号量不再需要时,将其从系统中删除。其定义如下:

int sem_unlink(const char *name);

其中,name为信号量的名字。

若函数执行成功,返回 0,失败返回-1。

7.举例

目的:实现父进程和子进程操作共享内存,其中子进程负责写入数据"你好,新年快乐",父进程负责读出共享数据"你好,新年快乐";并通过信号量进行同步,确保在任何时候只有一个进程可以访问共享内存。 

#include <stdio.h>  // 用于标准输入输出  
#include <stdlib.h>  // 用于常用库函数,如内存分配  
#include <string.h>  // 用于字符串操作函数  
#include <unistd.h>  // 用于底层系统调用,如fork()  
#include <sys/mman.h>  // 用于内存映射和信号量等系统调用  
#include <sys/wait.h>  // 用于等待子进程  
#include <semaphore.h>  // 用于信号量操作  
#include <sys/types.h>  
#include <sys/ipc.h>  
#include <sys/shm.h>  
#include <fcntl.h>  
  
int main(){  
    int shm;  // 共享内存标识符  
    key_t key;  // 用于创建共享内存的键值  
    pid_t pid;  // 进程ID  
    sem_t * sem=sem_open("/my_semaphore", O_CREAT, 0666, 1);  // 创建或打开一个信号量,初始值为1  
   
    char * buff;  // 指向共享内存的指针  
    key= ftok(".", 'R');  // 使用文件系统中的唯一键值创建键,用于创建共享内存对象  
    shm=shmget(key,1024,0666|IPC_CREAT);  // 获取共享内存标识符,如果需要则创建共享内存  
    buff=(char*)shmat(shm,NULL,0);  // 附加到共享内存并获取其地址  
   
    pid=fork();  // 创建子进程  
    if(pid<0){  // 如果fork()失败  
        perror("创建进程失败");  // 打印错误信息  
    }  
    else if(pid==0){  // 子进程代码块  
        printf("这是子进程\n");  
        sem_wait(sem);  // 子进程等待信号量,确保父进程先执行  
        printf("子进程锁住资源\n");  
        strcpy(buff,"你好,新年快乐");  // 向共享内存写入数据  
        printf("%s\n",buff);  // 打印共享内存中的数据  
        sem_post(sem);  // 子进程释放信号量,允许其他进程继续执行  
        printf("子进程释放资源\n");  
    }  
    else{  // 父进程代码块  
            printf("这是父进程\n");  
            sleep(1);  // 父进程等待1秒,确保子进程先执行  
            sem_wait(sem);  // 父进程等待信号量,确保子进程已经执行完毕  
            printf("父进程锁住资源\n");  
            printf("%s\n",buff);  // 打印共享内存中的数据  
            sem_post(sem);  // 父进程释放信号量,允许其他进程继续执行  
            printf("父进程释放资源\n");  
    }  
    sem_close(sem);  // 关闭信号量  
    sem_unlink("/my_semaphore");  // 删除信号量对象  
    shmdt(buff);  // 断开共享内存的连接,使其可以被系统回收  
    shmctl(shm,IPC_RMID,NULL);  // 删除共享内存对象  
}

 运行程序,得到结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值