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

shnhe 2024-06-15 16:07:02 阅读 65

在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); // 删除共享内存对象 }

 运行程序,得到结果:



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。