Linux进程编程(6)信号量编程
文章目录
前言(概念解释):
1.什么是信号,什么是信号量
信号和信号量是操作系统中用于进程间通信和同步的两个概念。
-
信号:
信号是操作系统用于通知进程发生了某个事件或条件的机制。它是一种异步通信方式,一个进程可以发送一个信号给另一个进程,后者在接收到信号后可以采取相应的操作。常见的信号包括SIGINT
(Ctrl+C中断信号)、SIGTERM
(终止信号)、SIGUSR1
(用户定义信号1)等。信号的处理可以由进程预先设置,通常是通过注册信号处理函数来处理不同的信号。 -
信号量:
信号量是一种用于同步多个进程访问共享资源的机制。信号量可以被看作是一个计数器,它可以被多个进程同时访问和操作。每当一个进程占用了某个资源,它会对信号量进行 P 操作(等待操作),这会导致信号量的值减少。当进程释放资源时,会对信号量进行 V 操作(信号操作),信号量的值增加。通过信号量,可以控制进程对共享资源的访问,以避免竞态条件和数据损坏。
在简单的说法中:
- 信号是一个进程间的通知机制,用于向进程发送事件发生的消息。
- 信号量是一个同步机制,用于控制多个进程对共享资源的访问。
2.其他概念解释
-
信号量集(Semaphore Set): 信号量集是一组信号量的集合,每个信号量都有一个唯一的标识号。在示例中,使用
semget
函数创建了一个信号量集。 -
键值(Key): 键值是一个用于标识信号量集的整数值,可以使用
ftok
函数生成。不同的键值对应不同的信号量集。 -
信号量标识符(Semaphore Identifier): 信号量标识符是用于标识信号量集的唯一值,通过
semget
函数创建或获取。 -
信号量值(Semaphore Value): 信号量的值表示资源的可用数量。在示例中,信号量的值被初始化为 1,表示资源可用。
-
信号量操作(Semaphore Operation): 信号量操作是对信号量进行 P(等待)操作和 V(释放)操作的过程。在示例中,使用
semop
函数进行信号量操作。 -
P 操作(Wait Operation): 也称为减操作,用于获取信号量。如果信号量值大于0,减少信号量值,允许进程继续执行;如果信号量值为0,进程等待,直到信号量值大于0。
-
V 操作(Signal Operation): 也称为增操作,用于释放信号量。增加信号量值,表示资源可用,允许等待的进程继续执行。
以下是一些常用的信号量:
-
Binary Semaphore(二元信号量): 值只能为0或1,用于实现互斥,例如用于独占访问共享资源。
-
Counting Semaphore(计数信号量): 值可以是任意非负整数,用于计数,例如用于限制资源的可用数量。
-
Mutex(互斥量): 一种特殊的二元信号量,用于实现互斥,通常用于线程同步。
-
Semaphore Array(信号量数组): 多个信号量的集合,可以一次性创建多个信号量。
-
Named Semaphore(命名信号量): 与信号量标识符不同,命名信号量使用可识别的名称作为标识符,可以跨进程/线程使用。
-
POSIX Semaphore(POSIX 信号量): 一种更高级的信号量实现,用于在不同操作系统间实现可移植的信号量编程。
一、信号量编程的各函数
1.联合体union semun
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
union semun
是一个联合体,用于在 System V IPC 机制中的信号量操作中传递参数。联合体的不同成员可以用于不同的操作,以便初始化、获取状态和设置状态等。
这里是各个成员的解释和用途:
-
int val
:- 含义:用于
SETVAL
操作,设置信号量的初始值。 - 作用:当使用
SETVAL
操作时,可以通过sem_arg.val
设置信号量的初始值。
- 含义:用于
-
struct semid_ds *buf
:- 含义:用于
IPC_STAT
和IPC_SET
操作,用于获取和设置信号量的属性。 - 作用:当使用
IPC_STAT
操作时,可以将信号量的属性存储在sem_arg.buf
中。当使用IPC_SET
操作时,可以将要设置的属性存储在sem_arg.buf
中。
- 含义:用于
-
unsigned short *array
:- 含义:用于
GETALL
和SETALL
操作,用于获取和设置信号量集中所有信号量的值。 - 作用:当使用
GETALL
操作时,可以将信号量集中所有信号量的值存储在sem_arg.array
中。当使用SETALL
操作时,可以将要设置的值存储在sem_arg.array
中。
- 含义:用于
-
struct seminfo *__buf
:- 含义:仅适用于 Linux 特定的
IPC_INFO
操作。 - 作用:用于获取信号量相关的信息,这是一个 Linux 特定的功能。
- 含义:仅适用于 Linux 特定的
总之,union semun
用于在 semctl
函数中指定参数,以根据不同的操作类型设置或获取信号量的不同属性。不同成员的使用取决于要执行的操作,以提供所需的信息。
2.常用信号
-
SIGINT (2): 当用户按下 Ctrl+C 时发送给进程的信号,用于中断(中止)程序。
-
SIGTERM (15): 请求终止进程的信号,通常由系统管理员或其他进程发送,进程可以捕获这个信号并做一些清理操作后退出。
-
SIGQUIT (3): 类似于 SIGINT,但用户按下 Ctrl+\ 时发送。进程可以捕获这个信号,用于请求进程退出并生成核心转储文件。
-
SIGHUP (1): 当终端关闭或连接断开时发送给进程的信号,通常用于通知进程重新加载配置或重新初始化。
-
SIGKILL (9): 强制终止进程的信号,进程无法捕获或忽略,通常用于紧急情况下终止进程。
-
SIGALRM (14): 由
alarm
函数设置的定时器到期时发送的信号,通常用于定时操作。 -
SIGUSR1 (10) 和 SIGUSR2 (12): 用户自定义的信号,进程可以捕获和处理,用于进程间通信或自定义操作。
-
SIGCHLD (17): 子进程状态改变时发送给父进程的信号,父进程可以捕获并处理。
-
SIGCONT (18): 继续执行停止的进程的信号,由
kill
命令发送。 -
SIGSTOP (19): 停止进程的信号,进程无法捕获或忽略,通常由系统管理员使用。
-
**SIG_IGN **: 是一个宏,表示忽略信号,在信号处理函数中,使用SIG_IGN表示将对应的信号忽略,需要注意的是,并不是所有信号都可以被忽略,某些关键性的信号,比如SIGKILL 和SIGSTOP都不能被忽略。
这些只是常见的信号,实际上有更多的信号在不同的操作系统中存在。信号用于进程间通信、控制和处理,可以用于中断进程、处理错误、同步进程等多种情况。
3.常见的标志和参数,以及它们的含义和用途
当使用 System V IPC(Inter-Process Communication)机制时,我们会经常看到一些标志或参数,如 IPC_CREAT
、0666
等。下面列出了一些常见的标志和参数,以及它们的含义和用途:
-
IPC_CREAT:
- 含义:用于创建一个新的 IPC 对象(如消息队列、信号量、共享内存)。
- 作用:如果指定了这个标志,系统将尝试创建一个新的 IPC 对象。如果对象已经存在,则会返回现有对象的标识符。
- 例子:
semget(key, nsems, IPC_CREAT | 0666)
创建一个新的信号量集,如果已存在则获取现有信号量集。
-
IPC_EXCL:
- 含义:与
IPC_CREAT
一起使用时,确保创建一个新的 IPC 对象。如果对象已经存在,则创建失败。 - 作用:避免意外重复创建相同的 IPC 对象。
- 例子:
semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666)
尝试创建一个新的信号量集,如果已存在则失败。
- 含义:与
-
IPC_NOWAIT:
- 含义:用于在进行某些操作时不阻塞。如果指定了这个标志,函数会立即返回,不会等待条件满足。
- 作用:可用于非阻塞地尝试获取锁或执行其他操作。
- 例子:
semop(semid, &sembuf, 1, IPC_NOWAIT)
非阻塞地执行信号量操作。
-
0666、0644 等:
- 含义:指定权限(权限掩码)。
- 作用:用于设置 IPC 对象的权限,规定谁能够访问和修改 IPC 对象。
- 例子:
semget(key, nsems, IPC_CREAT | 0666)
设置创建的信号量集的权限为读写。
这些标志和参数在创建和操作 IPC 对象时非常有用,它们决定了对象的创建、访问和修改权限,以及阻塞和非阻塞的操作方式。
4.常见命令(cmd)
当使用 System V IPC 机制时,我们会使用一些命令来控制和操作 IPC 对象,如获取状态、设置初始值等。下面列出了一些常见的命令,以及它们的含义和用途:
-
IPC_STAT:
- 含义:用于获取 IPC 对象的状态信息。
- 作用:允许进程查询 IPC 对象的状态,如获取共享内存的大小、获取信号量集的属性等。
- 例子:
semctl(semid, 0, IPC_STAT, &sem_ds)
获取信号量集的状态信息。
-
IPC_SET:
- 含义:用于设置 IPC 对象的状态。
- 作用:允许进程修改 IPC 对象的属性,如更改共享内存的权限、更改信号量集的大小等。
- 例子:
shmctl(shmid, IPC_SET, &shmid_ds)
设置共享内存的属性。
-
IPC_RMID:
- 含义:用于删除 IPC 对象。
- 作用:允许进程删除一个已经不再需要的 IPC 对象,释放其占用的资源。
- 例子:
semctl(semid, 0, IPC_RMID)
删除信号量集。
-
SETVAL:
- 含义:用于设置 IPC 对象的某些属性值,如信号量的初始值。
- 作用:初始化 IPC 对象的属性,例如,可以设置信号量集的初始值为某个特定值。
- 例子:
semctl(semid, semnum, SETVAL, sem_arg)
设置信号量的初始值。
-
GETALL:
- 含义:用于获取多个 IPC 对象的值。
- 作用:从 IPC 对象中一次性获取多个值,如从信号量集中获取所有信号量的值。
- 例子:
semctl(semid, 0, GETALL, sem_array)
获取信号量集中所有信号量的值。
-
SETALL:
- 含义:用于设置多个 IPC 对象的值。
- 作用:一次性设置多个 IPC 对象的属性,如将所有信号量的值设置为特定值。
- 例子:
semctl(semid, 0, SETALL, sem_array)
设置信号量集中所有信号量的值。
4.常用函数
-
semget - 创建或获取信号量集
int semget(key_t key, int nsems, int semflg);
- 返回值: 成功时返回信号量标识符(非负整数),失败时返回 -1。
- 作用: 用于创建一个新的信号量集或获取一个已存在的信号量集。
- 常用参数:
key
:用于标识信号量集的键值,通过ftok
函数生成。nsems
:指定要创建的信号量数量。semflg
:标志位,可以使用IPC_CREAT
表示创建信号量,还可以和其他标志位组合,如0666
权限等。
-
semctl - 控制信号量
int semctl(int semid, int semnum, int cmd, ...);
- 返回值: 成功时根据命令不同可能有不同的含义,失败时返回 -1。
- 作用: 用于控制信号量,执行操作如获取/设置信号量的值、删除信号量等。
- 常用参数:
semid
:信号量标识符,由semget
返回。semnum
:信号量在信号量集中的索引,通常为 0。cmd
:要执行的操作命令,如IPC_STAT
(获取信号量状态)、SETVAL
(设置初始值)等。- 可变参数:取决于命令,例如在
SETVAL
命令中使用,表示要设置的值。
-
semop - 执行信号量操作
int semop(int semid, struct sembuf *sops, unsigned nsops);
- 返回值: 成功时返回 0,失败时返回 -1。
- 作用: 用于执行一组信号量操作,如等待信号量(P 操作)和释放信号量(V 操作)。
- 常用参数:
semid
:信号量标识符,由semget
返回。sops
:指向sembuf
结构体数组的指针,每个操作包括信号量编号、操作类型和操作标志。nsops
:要执行的操作数量。
-
union semun - 用于信号量操作的联合体
union semun { int val; // 用于 SETVAL 命令 struct semid_ds *buf; // 用于 IPC_STAT 和 IPC_SET 命令 unsigned short *array; // 用于 GETALL 和 SETALL 命令 struct seminfo *__buf; // 用于 IPC_INFO 命令 };
- 作用: 用于在
semctl
函数中传递不同类型的参数,如设置信号量的初始值、获取信号量信息等。
- 作用: 用于在
-
struct sembuf - 信号量操作的数据结构
struct sembuf
是用于信号量操作的数据结构,用来指定对信号量的操作。在使用信号量编程时,我们通过设置struct sembuf
的成员来描述需要对信号量执行的操作,然后传递这个结构体给semop
函数来执行操作。
这个结构体定义如下:
struct sembuf {
unsigned short sem_num; // 信号量的索引(编号)
short sem_op; // 操作类型,通常是负值、零或正值
short sem_flg; // 操作的标志,比如 SEM_UNDO
};
sem_num
:指定操作的信号量在信号量集中的索引。"信号量集"中的信号量可以有多个,从 0 开始编号。sem_op
:指定操作的类型,通常是一个负值、零或正值。 负值表示等待(P 操作),零表示无操作,正值表示释放(V 操作)。sem_flg
:指定操作的标志,可以是 0 或者SEM_UNDO
。SEM_UNDO
表示在进程终止时应该撤消操作,以保证信号量的正确性。
在范例代码2中,你会看到这个结构体被用来描述 P 操作和 V 操作:
struct sembuf p_operation = {0, -1, SEM_UNDO}; // P 操作
struct sembuf v_operation = {0, 1, SEM_UNDO}; // V 操作
这两个结构体分别用于执行 P 操作和 V 操作,通过设置 sem_op
成员来表示等待或释放资源。
- srtuct sigaction结构体
struct sigaction
是用于处理信号的结构体,用于指定信号的处理方式和相关设置。在 UNIX/Linux 系统中,信号是用来通知进程发生了某个事件的一种机制。通过设置struct sigaction
结构体的成员,我们可以定义当特定信号发生时应该采取的操作,比如忽略信号、执行特定函数等。
这个结构体的定义如下:
struct sigaction {
void (*sa_handler)(int); // 信号处理函数
sigset_t sa_mask; // 阻塞的信号集合
int sa_flags; // 附加标志
void (*sa_sigaction)(int, siginfo_t *, void *); // 使用 sa_flags 指定的函数
};
sa_handler
:用于设置信号处理函数,当信号发生时会调用该函数。通常是一个函数指针,指向自定义的信号处理函数。sa_mask
:指定在信号处理函数执行期间阻塞的信号集合。这可以避免在信号处理函数执行时被其他信号中断。sa_flags
:用于指定附加标志,比如SA_RESTART
表示系统调用会在信号处理函数返回后自动重启。sa_sigaction
:用于指定一个信号处理函数,可以在sa_flags
中使用SA_SIGINFO
标志来启用。
在范例代码中,你会看到使用 struct sigaction
结构体来设置信号处理函数:
struct sigaction act;
act.sa_handler = SIG_IGN; // 忽略信号
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, NULL);
这段代码将信号 SIGINT
(通常是由 Ctrl+C 触发的中断信号)的处理方式设置为忽略。你还可以使用其他的信号处理方式,如自定义的信号处理函数等。
- sigaction函数
sigaction
是一个系统调用函数,用于设置和获取信号的处理方式。在 UNIX/Linux 系统中,进程可以通过 sigaction
函数来指定信号发生时的处理方式,比如执行自定义的信号处理函数、忽略信号、恢复默认处理等。
函数原型如下:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
signum
:要设置处理方式的信号编号。act
:一个指向struct sigaction
结构体的指针,用于设置新的信号处理方式。oldact
:一个指向struct sigaction
结构体的指针,用于获取之前的信号处理方式。
在 act
参数中,你可以设置 sa_handler
或 sa_sigaction
成员来指定信号发生时的处理方式。同时,你可以通过设置 sa_mask
成员来定义在信号处理函数执行期间需要阻塞的信号。还可以使用 sa_flags
来设置附加标志,如 SA_RESTART
等。
这个函数的返回值是 0
表示成功,-1
表示出现了错误。
在信号量编程中,sigaction
函数可以用来设置信号的处理方式,以及在某些情况下为信号处理函数提供更多的信息(使用 SA_SIGINFO
标志)。
二、范例代码
1.屏蔽Ctrl+C
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
int main() {
// 创建信号量集,只有一个信号量
int semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
if (semid == -1) {
perror("semget");
exit(EXIT_FAILURE);
}
// 初始化信号量的值为 1
union semun sem_arg;
sem_arg.val = 1;
if (semctl(semid, 0, SETVAL, sem_arg) == -1) {
perror("semctl");
exit(EXIT_FAILURE);
}
// 设置信号处理函数,屏蔽 Ctrl+C
struct sigaction act;
act.sa_handler = SIG_IGN; // 忽略信号
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, NULL);
printf("按下 Ctrl+C 不会中断程序。\n");
// 等待一个信号量操作,实际上这里是一个占位操作
struct sembuf sem_buf = {0, -1, 0}; // P 操作
semop(semid, &sem_buf, 1);
// 删除信号量集
if (semctl(semid, 0, IPC_RMID) == -1) {
perror("semctl");
exit(EXIT_FAILURE);
}
return 0;
}
解释和注释:
-
semget(IPC_PRIVATE, 1, IPC_CREAT | 0666)
:创建一个只有一个信号量的信号量集。IPC_PRIVATE
生成一个新的唯一键值。如果创建失败,输出错误信息并退出。 -
union semun sem_arg; sem_arg.val = 1;
:定义一个联合体变量sem_arg
,用于后续设置信号量的初始值为 1。 -
semctl(semid, 0, SETVAL, sem_arg)
:使用semctl
函数将信号量的初始值设置为 1。 -
struct sigaction act; act.sa_handler = SIG_IGN; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL);
:设置信号处理函数,使得进程忽略 Ctrl+C(SIGINT)信号。 -
printf("按下 Ctrl+C 不会中断程序。\n");
:打印提示信息,说明按下 Ctrl+C 不会中断程序。 -
struct sembuf sem_buf = {0, -1, 0};
:定义一个sembuf
结构体,其中sem_num
是信号量索引,sem_op
是操作值(-1 表示执行 P 操作),sem_flg
是标志位(0 表示无特殊标志)。 -
semop(semid, &sem_buf, 1);
:执行信号量操作,尝试执行一个 P 操作,但实际上是一个占位操作。 -
semctl(semid, 0, IPC_RMID)
:删除之前创建的信号量集。
总结信号量编程的通用步骤:
- 使用
semget
函数创建信号量集,设置标志和权限。 - 使用
semctl
函数初始化或设置信号量的值和属性。 - 使用
sigaction
函数设置信号处理函数,控制信号的行为。 - 执行信号量操作(P 操作或 V 操作)来控制资源的访问。
- 使用
semctl
函数删除信号量集,释放资源。
2. P操作和V操作
P 操作和 V 操作是信号量编程中常用的两种操作,用于实现资源的同步和互斥。它们都是对信号量进行操作的方式,以下是对它们的详细解释:
P 操作(等待操作):
P 操作是一种请求操作,它试图从信号量中获得资源。如果信号量的值大于零,即资源可用,那么 P 操作会减少信号量的值,并且程序可以继续执行。如果信号量的值等于零,即资源已经被占用,那么 P 操作会使当前进程等待,直到资源被释放。
在代码中,P 操作使用的结构体是:
struct sembuf p_operation = {0, -1, SEM_UNDO};
这里的 -1
表示尝试获取一个资源。0
表示要操作的信号量的索引,即信号量集中的第一个信号量。
V 操作(释放操作):
V 操作是一种释放操作,它将资源放回信号量中。V 操作会增加信号量的值,表示资源已经被释放。如果有其他等待该资源的进程,它们将有机会获取资源并继续执行。
在代码中,V 操作使用的结构体是:
struct sembuf v_operation = {0, 1, SEM_UNDO};
这里的 1
表示释放一个资源。0
仍然表示要操作的信号量的索引。
SEM_UNDO 标志:
SEM_UNDO
标志用于表示操作完成后应该自动撤消操作,以防止因进程突然终止而导致的信号量不正确的问题。
在范例代码中,你可以看到 P 操作和 V 操作的使用:
semop(semid, &p_operation, 1); // P 操作
// ...
semop(semid, &v_operation, 1); // V 操作
总结来说,P 操作和 V 操作是通过信号量来实现资源同步和互斥的核心机制。P 操作尝试获取资源,如果资源不可用,进程会等待。V 操作释放资源,使其他等待资源的进程有机会获取。这两种操作的结合确保了进程间的合理协调,以及对共享资源的正确使用。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
// 信号量操作结构体
struct sembuf p_operation = {0, -1, SEM_UNDO};
struct sembuf v_operation = {0, 1, SEM_UNDO};
int main() {
// 创建一个键值
key_t key = ftok(".", 'S');
// 获取/创建一个信号量
int semid = semget(key, 1, IPC_CREAT | 0666);
if (semid == -1) {
perror("semget");
exit(EXIT_FAILURE);
}
// 初始化信号量的值为 1
if (semctl(semid, 0, SETVAL, 1) == -1) {
perror("semctl");
exit(EXIT_FAILURE);
}
int pid = fork();
if (pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程
printf("子进程尝试获取资源...\n");
semop(semid, &p_operation, 1); // P 操作
printf("子进程获得了资源,开始执行任务...\n");
sleep(2); // 模拟子进程执行任务
printf("子进程任务完成,释放资源...\n");
semop(semid, &v_operation, 1); // V 操作
exit(EXIT_SUCCESS);
} else {
// 父进程
printf("父进程尝试获取资源...\n");
semop(semid, &p_operation, 1); // P 操作
printf("父进程获得了资源,开始执行任务...\n");
sleep(2); // 模拟父进程执行任务
printf("父进程任务完成,释放资源...\n");
semop(semid, &v_operation, 1); // V 操作
wait(NULL); // 等待子进程结束
// 删除信号量
semctl(semid, 0, IPC_RMID);
}
return 0;
}
总结
信号量编程是一种在多进程/线程环境中实现进程同步、互斥和资源共享的编程技术。以下是关键要点的总结:
-
信号量: 信号量是一个计数器,用于控制多进程对共享资源的访问。它支持 P 操作(申请资源)和 V 操作(释放资源)。
-
P 操作和 V 操作: P 操作用于等待资源,V 操作用于释放资源。这两者共同协调进程对资源的访问。
-
创建和初始化: 使用
semget
和semctl
函数创建和初始化信号量。可以设置初始值和属性。 -
资源同步: 信号量用于协调进程执行顺序,避免竞态条件。P 操作使进程等待,直到资源可用。
-
资源互斥: 信号量确保一次只有一个进程可以访问共享资源。V 操作允许其他进程获得资源。
-
资源共享: 信号量也用于控制多个进程/线程对共享资源的访问,确保资源正确分配和释放。
-
进程同步: 通过信号量可以实现进程之间的同步,确保它们在正确的时机执行。
-
应用场景: 适用于需要多个进程/线程协同工作、资源共享的情况,如控制文件访问、共享内存、网络资源等。
-
注意事项: 信号量编程需要小心设计,以避免死锁和资源泄漏。
-
步骤总结:
- 创建信号量:使用
semget
函数创建信号量集。 - 初始化信号量:使用
semctl
函数初始化信号量值和属性。 - 执行操作:使用
semop
函数执行 P 操作和 V 操作。 - 设置信号处理:使用
sigaction
函数设置信号处理函数,控制信号行为。 - 删除信号量:使用
semctl
函数删除信号量集,释放资源。
综上所述,信号量编程是一种强大的并发编程技术,用于实现多进程/线程的同步、互斥和资源管理,确保程序在复杂并发环境下的正确性和稳定性。