内存信号量sem_init函数解析

本文解析了sem_init函数中pshared参数的作用,介绍了如何通过设置该参数实现线程间或进程间的信号量共享,并提供了示例代码。

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

int	sem_init(sem_t *sem, int pshared, unsigned int value);
return 0 on success,or -1 on error

本文着重解析sem_init第二个参数 pshared ,下面摘自《The Linux Programming Interface》
这一段大体意思:如果pshared是0 则可以在线程间共享
如果非0,则可以在进程间共享,但是有个条件:信号量必须存在于共享内存中
也就是说并非pshared非0就可以实现进程间共享,示例如下:

#include <stdio.h>
#include <errno.h>
#include <semaphore.h>
#include <fcntl.h>
sem_t sem; 
static void mysem(char *str)
{
 int i = 0;
 while('\0' != str[i])
 {
  printf("%c\n", str[i++]);
  sleep(1);
 }
}
int main(void) 
{
 pid_t pid = -1;
 int ret = -1;
 int status = -1;
 int semvalue;
                                                                                                       sem_init(&sem,0,1);
 pid = fork();
 if(-1 == (ret = pid))
 {
  perror("fork failed: ");
  goto _OUT;
 }
                                                                                                                                                                                                                                                                                                                                                                       
 if(0 == pid)
 {
  mysem("abcd");
printf("2sem address is %x\r\n",&sem);
sem_getvalue(&sem,&ret);
printf("1sem ret is %d\r\n",ret);
  ret = sem_post(&sem);
  sem_getvalue(&sem,&ret);
printf("2sem ret is %d\r\n",ret);
  ret = sem_post(&sem);
  sem_getvalue(&sem,&ret);
printf("2.5sem ret is %d\r\n",ret);
 }
 if(0 < pid)
 {
printf("1sem address is %x\r\n",&sem);
  wait(&status);
  sem_getvalue(&sem,&ret);
printf("3sem ret is %d\r\n",ret);
  ret = sem_wait(&sem);
  mysem("1234");
  ret = sem_wait(&sem);
  sem_getvalue(&sem,&ret);
printf("4sem ret is %d\r\n",ret);
  mysem("5678");
  sem_destroy(&sem);
 }
_OUT:
 return ret;
}
[meteor@localhost sem]$ ./sem_ram_syn
1sem address is 804a044
a
b
c
d
2sem address is 804a044
1sem ret is 1
2sem ret is 2
2.5sem ret is 3
3sem ret is 1
1
2
3
4
^C

仔细分析打印结果可以发现,父进程(pid>0)中sem的值只与sem_init初始化的值有关,不管子进程中
有多少次post,父进程依然会锁住,并不会打印“5678”
具体进程间共享暂未实现,有时间再补上

线程间共享:

#include <stdio.h>
#include <errno.h>
#include <semaphore.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#define SEM_NAME "mysem"
#define OPEN_FLAG O_RDWR|O_CREAT
#define OPEN_MODE 00777
#define INIT_V 0
 sem_t sem;
static void mysem(char *str)
{
 int i = 0;
 while('\0' != str[i])
 {
  printf("%c\n", str[i++]);
  sleep(1);
 }
}
void *thrd_func()
{
 int ret = -1;
       
 mysem("abcd");
 sem_getvalue(&sem,&ret);
 printf("1sem ret is %d\r\n",ret);
 ret = sem_post(&sem);
 sem_getvalue(&sem,&ret);
 printf("2sem ret is %d\r\n",ret);
 ret = sem_post(&sem);
 sem_getvalue(&sem,&ret);
 printf("2.5sem ret is %d\r\n",ret);
}
int main(void)
{
 pid_t pid = -1;
 int ret = -1;
 int status = -1;
 int semvalue;
 pthread_t tid;
 
 sem_init(&sem,0,0);
  pthread_create(&tid,NULL, thrd_func, NULL);
sleep(10);
 sem_getvalue(&sem,&ret);
printf("3sem ret is %d\r\n",ret);
 ret = sem_wait(&sem);
 sem_getvalue(&sem,&ret);
printf("4sem ret is %d\r\n",ret);
 mysem("1234");
 ret = sem_wait(&sem);
 sem_getvalue(&sem,&ret);
printf("5sem ret is %d\r\n",ret);
 mysem("5678");
 sem_destroy(&sem);
 return 0;
}

[meteor@localhost sem]$ ./sem_ram_thread
a
b
c
d
1sem ret is 0
2sem ret is 1
2.5sem ret is 2
3sem ret is 2
4sem ret is 1
1
2
3
4
5sem ret is 0
5
6
7
8
[meteor@localhost sem]$


线程间用锁

#include <stdio.h>
#include <errno.h>
#include <semaphore.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#define SEM_NAME "mysem"
#define OPEN_FLAG O_RDWR|O_CREAT
#define OPEN_MODE 00777
#define INIT_V 0
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 sem_t sem;
static void mysem(char *str)
{
 int i = 0;
 while('\0' != str[i])
 {
  printf("%c\n", str[i++]);
  sleep(1);
 }
}
void *thrd_func()
{
 int ret = -1;
 pthread_mutex_unlock(&mutex);
 pthread_mutex_unlock(&mutex);
 mysem("abcd");
sleep(20);
 pthread_mutex_unlock(&mutex);
}
int main(void)
{
 pid_t pid = -1;
 int ret = -1;
 int status = -1;
 int semvalue;
 pthread_t tid;
 
 pthread_create(&tid,NULL, thrd_func, NULL);
sleep(10);
 pthread_mutex_lock(&mutex);
 mysem("1234");
 pthread_mutex_lock(&mutex);
 mysem("5678");
 sem_destroy(&sem);
 return 0;
}


[meteor@localhost sem]$ ./lock_thread
a
b
c
d
1
2
3
4
5
6
7
8
[meteor@localhost sem]$


可见,跟信号量不同的一点,子线程不管解锁多少次,主线程一次lock就可以了,后面不会执行
只有子进程(延迟解锁)解锁,才会继续进行


### 关于 `sem_init` 函数的详细解释和用法 #### 1. 功能概述 `sem_init` 是 POSIX 标准中定义的一个函数,主要用于初始化一个信号量Semaphore),该信号量可用于进程间或线程间的同步机制。通过协调多个线程或进程对共享资源的访问,信号量能够有效防止竞争条件的发生。 #### 2. 函数原型 以下是 `sem_init` 的函数声明: ```c #include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); ``` - **参数说明** - `sem_t *sem`: 指向要初始化的信号量对象的指针。 - `int pshared`: 表示信号量的作用范围。如果值为 `0`,则表示此信号量仅限于当前进程内的线程共享;如果是非零值,则表示此信号量可以在不同进程之间共享[^2]。 - `unsigned int value`: 设置信号量的初始值。通常用来控制可并发访问某个资源的最大数量[^1]。 - **返回值**: 成功时返回 `0`,失败时返回 `-1` 并设置相应的错误码到 `errno` 中。 #### 3. 使用场景 - 当需要在线程内部实现互斥锁功能时,可以通过将 `pshared` 设定为 `0` 来创建一个线程局部的信号量。 - 如果希望跨进程通信并管理公共资源,则需设定 `pshared` 不等于 `0`,并将信号量置于共享内存区段内[^4]。 #### 4. 示例代码 下面展示如何利用 `sem_init` 实现基本的线程同步: ```c #include <pthread.h> #include <semaphore.h> #include <stdio.h> #include <stdlib.h> #define NUM_THREADS 5 // 定义全局信号量变量 sem_t my_semaphore; void* thread_function(void* arg) { // 线程尝试获取信号量 if (sem_wait(&my_semaphore) != 0) { // 尝试减少信号量计数器 perror("sem_wait failed"); exit(EXIT_FAILURE); } printf("Thread %ld is running\n", (long)arg); // 执行一些工作... // 增加信号量计数器 if (sem_post(&my_semaphore) != 0) { // 发布信号给其他等待者 perror("sem_post failed"); exit(EXIT_FAILURE); } pthread_exit(NULL); } int main() { pthread_t threads[NUM_THREADS]; long i; // 初始化信号量,允许最多只有一个线程进入临界区 if (sem_init(&my_semaphore, 0, 1) != 0) { // 这里我们只让单一线程运行 perror("sem_init failed"); exit(EXIT_FAILURE); } for(i = 0; i < NUM_THREADS; ++i){ if(pthread_create(&threads[i], NULL, thread_function, (void*)i)){ fprintf(stderr,"Error creating thread %ld\n", i); exit(EXIT_FAILURE); } } for(i = 0; i < NUM_THREADS; ++i){ pthread_join(threads[i], NULL); } // 销毁信号量 if (sem_destroy(&my_semaphore) != 0){ perror("sem_destroy failed"); } return EXIT_SUCCESS; } ``` #### 5. 注意事项 - 调用 `sem_init` 后,在不再需要使用信号量之前应调用 `sem_destroy` 来销毁它,以释放相关联的任何系统资源[^3]。 - 对同一个已经被初始化过的信号量再次调用 `sem_init` 可能会产生未定义行为。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值