Linux c 信号量

本文深入讲解了信号量机制,包括其基本概念、编程模型及实际应用案例。通过具体代码示例,介绍了如何创建、初始化、操作及删除信号量,帮助读者理解进程间同步的基本原理。

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

信号量(通过进程通信实现进程间的同步)

信号量(semaphore)信号灯

信号量是共享内存整数数组.根据需要定义指定的数组长度

信号量就是根据数组中的值,决定阻塞还是解除阻塞

编程模型:

1. 创建或者得到信号量 semget

2. 初始化信号量中指定下标的值 semctl

3. 根据信号量阻塞或者解除阻塞 semop

4. 删除信号量 semctl

案例:

A: B:

创建信号量 得到信号量

初始化信号量 解除阻塞

根据信号量阻塞

删除信号量

int semget(key_t key,

int nums,//信号量数组个数

int flags);//信号量的创建标记

//创建IPC_CREAT|IPC_EXCL|0666

//打开0

返回: -1:失败

>=0:成功返回信号量的ID

int semctl(int semid,

intnums,//对IPC_RMID无意义

intcmd,//SETVAL(信号量值)IPC_RMID

...);//对IPC_RMID无意义

参数:
semid:信号集的标识符,即是信号表的索引。
semnum:信号集的索引,用来存取信号集内的某个信号。
cmd:需要执行的命令,有效值有 需要使用联合体semun赋值

union semun{

int val;

struct semid_ds *buf;

unsigned short *array;

struct seminfo *_buf;

};//需要自己定义该联合体,根据需要定义,需要那个字段就可以只定义那个

int semop(

int semid,//信号量ID

struct sembuf*op,//对信号量的操作.操作可以是数组多个

size_tnums,//第二个参数的个数

);

返回:

-1:时失败

0:成功

struct sembuf

{

int sem_num;//下标

int sem_op;

int sem_flg;//建议为0.

}


sem_op:
前提条件信号量是unsigned short int;
不能<0.
-:够减,则semop马上返回,不够减,则阻塞.
+:执行+操作
0:判定信号量>0,则阻塞,直到为0
控制进程的搭配方式:
+(解除阻塞) -(阻塞)
0(阻塞) -(解除阻塞)

代码:

semA:

#include<stdio.h>

#include<unistd.h>

#include<sys/ipc.h>

#include<sys/sem.h>

#include<stdlib.h>

#include<signal.h>

int semid;

void deal(ints)

{

//4.删除信号量

printf(“删除信号量…”);

semctl(semid,0,IPC_RMID , 0);

printf(“信号量已删除”);

exit( -1 );

}

union semun{

int val;

struct semid_ds *buf;

unsigned short *array;

struct seminfo *_buf;

};

void main()

{

key_tkey;

union semun v;//2.2定义初始化值

int r;

//3.1定义一个操作结构体

structsembuf op[1]; //定义了两个操作

signal(SIGINT , deal);

//1.创建信号量

key=ftok(“.” , 99);

if(key == -1) printf(“ftok err :%m\n”) ,exit(-1);

semid=semget(kay,1 /*信号量数组个数*/ , IPC_CREAT | IPC_EXCL | 0666);

if( semget == -1) printf(“get err %m\n”) ,exit(-1);

//2.初始化信号量

//2.1定义一个联合体

v.val=2;

r=semctl(semid , 0 , SETVAL , v); //设置信号量的值

if(r== -1) printf(“初始化失败:%m\n”) , exit(-1);

//3.对信号量阻塞操作

op[0].sem_num=0; //信号量的下标

op[0].sem_op= 1; //信号量操作单位与类型

op[0].sem_flg=0; //操作标记 IPC_NOWAIT(信号量值够不够减都返回 不阻塞)

//SEM_UNDO 建议为0;

while(1)

{

r=semop(semid , op ,1);

printf(“信号量阻塞-1”);

}

}

//semop操作减一 ,信号量值大于0,semop执行返回,信号量值等于0时,semop操作阻塞等待,直到信号量值大于0,在进行该操作

semB:

#include<stdio.h>

#include<unistd.h>

#include<sys/ipc.h>

#include<sys/sem.h>

#include<stdlib.h>

union semun{

int val;

struct semid_ds *buf;

unsigned short *array;

struct seminfo *_buf;

};

void main()

{

intsemid;

key_tkey;

int r;

//3.1定义一个操作结构体

structsembuf op[1]; //定义了两个操作

signal(SIGINT , deal);

//1.得到信号量

key=ftok(“.” , 99);

if(key == -1) printf(“ftok err :%m\n”) ,exit(-1);

semid=semget(kay,1 /*信号量数组个数*/ ,0);

if( semget == -1) printf(“get err %m\n”) ,exit(-1);

//3.对信号量阻塞操作

op[0].sem_num=0; //信号量的下标

op[0].sem_op= +1; //信号量操作单位与类型

op[0].sem_flg=0; //操作标记 IPC_NOWAIT(信号量值够不够减都返回 不阻塞)

//SEM_UNDO 建议为0;

while(1)

{

r=semop(semid , op ,1);

sleep(1);

}

}

//进程semA进行信号量阻塞-1 semB进行信号量接触阻塞+1 , semB进程控制semA进程的执行

### Linux C 中信号量的使用教程 #### 1. 基本概念 信号量是一种进程间通信机制,主要用于实现多线程或多进程环境下的资源同步和互斥访问。它可以通过计数值来表示可用资源的数量或者协调多个线程之间的顺序关系。 在 Linux 的系统调用中,提供了 `semget`、`semop` 和 `semctl` 函数来管理信号量[^2]。这些函数分别用于创建或访问信号量集合、对信号量执行操作以及对其进行控制。 --- #### 2. 需要包含的头文件 为了使用信号量功能,程序需要引入以下头文件: ```c #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> ``` 上述头文件包含了信号量相关的数据结构和函数声明[^3]。 --- #### 3. 主要函数说明 ##### (1) 创建或访问信号量集 —— `semget` 该函数通过指定的关键字 (`key`) 来创建一个新的信号量集或将现有的信号量集附加到当前进程中。 ```c int semget(key_t key, int nsems, int semflg); ``` - 参数解释: - `key`: 由 `ftok()` 函数生成的一个唯一键值。 - `nsems`: 要创建的信号量数量。 - `semflg`: 控制标志位(如权限设置),通常会与 `IPC_CREAT` 或 `IPC_EXCL` 结合使用。 示例代码片段如下: ```c key_t key = ftok("/tmp", 'a'); // 使用路径 "/tmp" 和项目 ID 'a' 生成唯一的 key if (key == -1) { perror("ftok"); exit(EXIT_FAILURE); } int semid = semget(key, 1, IPC_CREAT | 0666); // 创建一个信号量集 if (semid == -1) { perror("semget"); exit(EXIT_FAILURE); } ``` --- ##### (2) 对信号量执行操作 —— `semop` 此函数允许对信号量进行原子性的增减操作。 ```c int semop(int semid, struct sembuf sops[], size_t nsops); ``` - 参数解释: - `semid`: 信号量集的标识符。 - `sops[]`: 定义了一系列的操作数组,其中每个元素是一个 `struct sembuf` 类型的对象。 - `nsops`: 数组中的操作数。 以下是 `sembuf` 数据结构的定义: ```c struct sembuf { unsigned short sem_num; // 信号量编号 short sem_op; // 操作类型 (+/-) short sem_flg; // 操作标志 (e.g., SEM_UNDO) }; ``` 示例代码片段如下: ```c struct sembuf sop; sop.sem_num = 0; // 表示第一个信号量 sop.sem_op = -1; // P 操作 (-1),尝试减少信号量值 sop.sem_flg = SEM_UNDO;// 如果失败则自动恢复原状态 // 执行 P 操作 if (semop(semid, &sop, 1) == -1) { perror("semop(P)"); } // V 操作 (+1),释放锁并增加信号量值 sop.sem_op = +1; if (semop(semid, &sop, 1) == -1) { perror("semop(V)"); } ``` --- ##### (3) 控制信号量行为 —— `semctl` 这个函数可以用来初始化、查询或销毁信号量。 ```c int semctl(int semid, int semnum, int cmd, ... /* union semun arg */ ); ``` - 参数解释: - `semid`: 信号量集的标识符。 - `semnum`: 特定信号量的索引号。 - `cmd`: 指令类型(如 `SETVAL`, `GETVAL`, `IPC_RMID` 等)。 - `arg`: 可选参数,具体取决于指令的内容。 示例代码片段如下: ```c union semun { int val; // SETVAL 初始化时使用的整数值 struct semid_ds *buf; // IPC_STAT/IPC_SET 获取或设置信号量元信息 unsigned short *array; // GETALL/SETALL 设置整个信号量集的值 }; // 将信号量初始值设为 1 union semun init_arg; init_arg.val = 1; if (semctl(semid, 0, SETVAL, init_arg) == -1) { perror("semctl(SETVAL)"); } ``` --- #### 4. 生产者-消费者问题示例代码 下面展示了一个完整的生产者-消费者模型,利用信号量实现了线程间的同步: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #define BUFFER_SIZE 5 key_t key = ftok("/tmp", 'b'); int semid; void initialize_semaphore() { semid = semget(key, 2, IPC_CREAT | 0666); if (semid == -1) { perror("semget"); exit(EXIT_FAILURE); } union semun { int val; } init_arg; init_arg.val = 0; // empty semaphore 初始值为 0 if (semctl(semid, 0, SETVAL, init_arg) == -1) { perror("semctl(empty)"); exit(EXIT_FAILURE); } init_arg.val = BUFFER_SIZE; // full semaphore 初始值为缓冲区大小 if (semctl(semid, 1, SETVAL, init_arg) == -1) { perror("semctl(full)"); exit(EXIT_FAILURE); } } void perform_p_operation(int sem_num) { struct sembuf sop; sop.sem_num = sem_num; sop.sem_op = -1; sop.sem_flg = SEM_UNDO; if (semop(semid, &sop, 1) == -1) { perror("P operation failed"); exit(EXIT_FAILURE); } } void perform_v_operation(int sem_num) { struct sembuf sop; sop.sem_num = sem_num; sop.sem_op = +1; sop.sem_flg = SEM_UNDO; if (semop(semid, &sop, 1) == -1) { perror("V operation failed"); exit(EXIT_FAILURE); } } void* producer(void* args) { while (1) { printf("Producer is producing...\n"); // Perform P on the "full" semaphore to check buffer space. perform_p_operation(1); // Simulate production logic here... // Perform V on the "empty" semaphore after adding an item. perform_v_operation(0); sleep(rand() % 3); // Random delay between productions. } } void* consumer(void* args) { while (1) { printf("Consumer is consuming...\n"); // Perform P on the "empty" semaphore before removing an item. perform_p_operation(0); // Simulate consumption logic here... // Perform V on the "full" semaphore after freeing a slot. perform_v_operation(1); sleep(rand() % 3); // Random delay between consumptions. } } int main() { pthread_t prod_thread, cons_thread; srand(time(NULL)); initialize_semaphore(); pthread_create(&prod_thread, NULL, producer, NULL); pthread_create(&cons_thread, NULL, consumer, NULL); pthread_join(prod_thread, NULL); pthread_join(cons_thread, NULL); return 0; } ``` --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值