linux下C的 信号量 函数(sem开头的那一簇)的实践

这篇博客介绍了Linux环境下,使用C语言实现信号量(semaphore)进行进程间通信的实践。通过信号量实现进程互斥,解决进程A和B交替执行的问题,确保在任意时刻只有一个进程运行。涉及的主要函数包括ftok、semget、semctl和semop等,以及具体的场景解决方案。

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

linux下C的 信号量 函数(sem开头的那一簇)的实践


这是一种IPC(InterProcess Communication),进程间相互通信的技术。

信号量semaphore是一种操作系统管理的计数器,需要配合的多个进程,通过获取、创建、赋值、等待(消耗)同一个信号量,可以实现进程互斥、临界区保护、锁、生产者消费者模式等


主要的函数列表:

  • ftok:生成获取信号量的键值,以方便不同的进程获取到同一个信号量()
  • semget:获取、创建信号量
  • semctl:赋值、删除信号量
  • semop:等待 (消耗)信号量
  • semtimedop:带超时功能的等待(消耗)信号量

实际要解决的问题场景:

  • 进程A的过程funca循环执行;
### 使用信号量 `sem` 的基本方法 #### 1. **无名信号量** 无名信号量通常用于线程间的同步,因为它不需要文件系统的支持[^1]。以下是使用无名信号量的关键步骤: - **初始化信号量** 调用 `sem_init()` 函数来初始化一个无名信号量。该函数原型如下: ```c int sem_init(sem_t *sem, int pshared, unsigned int value); ``` 参数说明: - `sem`: 指向信号量的指针。 - `pshared`: 如果为 `0`,则表示此信号量仅限于同一进程内的多个线程之间共享;如果为非零,则可以跨进程共享[^2]。 - `value`: 设置信号量的初始值。 - **P/V 操作** P 操作(等待操作)和 V 操作(释放操作)分别由 `sem_wait()` 和 `sem_post()` 实现。它们的作用分别是减少信号量计数器以及增加信号量计数器。 ```c int sem_wait(sem_t *sem); // 等待信号量 int sem_post(sem_t *sem); // 增加信号量 ``` - **销毁信号量** 当不再需要信号量时,调用 `sem_destroy()` 来释放资源。 ```c int sem_destroy(sem_t *sem); ``` 下面是一个简单的线程同步示例代码: ```c #include <pthread.h> #include <semaphore.h> #include <stdio.h> sem_t mutex; void* thread_func(void* arg) { printf("Thread waiting...\n"); sem_wait(&mutex); // 等待信号量 printf("Thread got the semaphore!\n"); return NULL; } int main() { pthread_t tid; sem_init(&mutex, 0, 0); // 初始化信号量,初值设为 0 pthread_create(&tid, NULL, thread_func, NULL); sleep(1); // 主线程延迟一段时间后再发出信号 printf("Main thread posting semaphore\n"); sem_post(&mutex); // 发送信号给子线程 pthread_join(tid, NULL); sem_destroy(&mutex); // 销毁信号量 return 0; } ``` --- #### 2. **有名信号量** 有名信号量适用于进程间通信,它通过名称识别并存储在文件系统中[^4]。下面是其主要功能及其实现方式: - **创建或打开信号量** 使用 `sem_open()` 创建一个新的有名信号量或者打开已存在的信号量。 ```c sem_t* sem_open(const char *name, int oflag, ... /* mode_t mode, unsigned int value */ ); ``` 参数解释: - `name`: 信号量的名字,通常是 `/` 开头的字符串。 - `oflag`: 定义行为标志位,比如 `O_CREAT` 表明如果不存在就创建新信号量。 - 可选参数:指定权限模式 (`mode`) 和初始值 (`value`)。 - **关闭信号量** 使用 `sem_close()` 关闭一个已经打开的信号量对象。 ```c int sem_close(sem_t *sem); ``` - **删除信号量** 删除一个有名信号量可以通过 `sem_unlink()` 实现。 ```c int sem_unlink(const char *name); ``` 以下是一段演示进程间同步的例子: ```c #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For mode constants */ #include <semaphore.h> #include <stdio.h> #include <unistd.h> #define SEM_NAME "/my_semaphore" int main() { sem_t *sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, 0644, 0); // 初始值设置为 0 if (sem == SEM_FAILED) { perror("Failed to create semaphore"); return 1; } pid_t pid = fork(); if (pid == 0) { // 子进程 printf("[Child] Waiting for signal from parent.\n"); sem_wait(sem); // 阻塞直到父进程发送信号 printf("[Child] Got the signal! Exiting now.\n"); } else { // 父进程 sleep(2); // 让子进程先运行一会儿 printf("[Parent] Posting semaphore and exiting.\n"); sem_post(sem); // 向子进程发信号 } sem_close(sem); // 关闭信号量 sem_unlink(SEM_NAME); // 删除信号量 return 0; } ``` --- ### 总结 无论是无名还是有名的信号量,在 Linux 中都可以用来解决并发环境下的同步问题。对于线程而言,推荐优先考虑更轻便高效的无名信号量[^3];而对于不同进程之间的协调工作,则更适合采用基于文件系统的有名信号量[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值