Linux进程编程(6)信号量编程

Linux进程编程(6)信号量编程


前言(概念解释):

1.什么是信号,什么是信号量

信号和信号量是操作系统中用于进程间通信和同步的两个概念。

  1. 信号:
    信号是操作系统用于通知进程发生了某个事件或条件的机制。它是一种异步通信方式,一个进程可以发送一个信号给另一个进程,后者在接收到信号后可以采取相应的操作。常见的信号包括 SIGINT(Ctrl+C中断信号)、SIGTERM(终止信号)、SIGUSR1(用户定义信号1)等。信号的处理可以由进程预先设置,通常是通过注册信号处理函数来处理不同的信号。

  2. 信号量:
    信号量是一种用于同步多个进程访问共享资源的机制。信号量可以被看作是一个计数器,它可以被多个进程同时访问和操作。每当一个进程占用了某个资源,它会对信号量进行 P 操作(等待操作),这会导致信号量的值减少。当进程释放资源时,会对信号量进行 V 操作(信号操作),信号量的值增加。通过信号量,可以控制进程对共享资源的访问,以避免竞态条件和数据损坏。

在简单的说法中:

  • 信号是一个进程间的通知机制,用于向进程发送事件发生的消息。
  • 信号量是一个同步机制,用于控制多个进程对共享资源的访问。

2.其他概念解释

  1. 信号量集(Semaphore Set): 信号量集是一组信号量的集合,每个信号量都有一个唯一的标识号。在示例中,使用 semget 函数创建了一个信号量集。

  2. 键值(Key): 键值是一个用于标识信号量集的整数值,可以使用 ftok 函数生成。不同的键值对应不同的信号量集。

  3. 信号量标识符(Semaphore Identifier): 信号量标识符是用于标识信号量集的唯一值,通过 semget 函数创建或获取。

  4. 信号量值(Semaphore Value): 信号量的值表示资源的可用数量。在示例中,信号量的值被初始化为 1,表示资源可用。

  5. 信号量操作(Semaphore Operation): 信号量操作是对信号量进行 P(等待)操作和 V(释放)操作的过程。在示例中,使用 semop 函数进行信号量操作。

  6. P 操作(Wait Operation): 也称为减操作,用于获取信号量。如果信号量值大于0,减少信号量值,允许进程继续执行;如果信号量值为0,进程等待,直到信号量值大于0。

  7. V 操作(Signal Operation): 也称为增操作,用于释放信号量。增加信号量值,表示资源可用,允许等待的进程继续执行。

以下是一些常用的信号量:

  1. Binary Semaphore(二元信号量): 值只能为0或1,用于实现互斥,例如用于独占访问共享资源。

  2. Counting Semaphore(计数信号量): 值可以是任意非负整数,用于计数,例如用于限制资源的可用数量。

  3. Mutex(互斥量): 一种特殊的二元信号量,用于实现互斥,通常用于线程同步。

  4. Semaphore Array(信号量数组): 多个信号量的集合,可以一次性创建多个信号量。

  5. Named Semaphore(命名信号量): 与信号量标识符不同,命名信号量使用可识别的名称作为标识符,可以跨进程/线程使用。

  6. 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 机制中的信号量操作中传递参数。联合体的不同成员可以用于不同的操作,以便初始化、获取状态和设置状态等。

这里是各个成员的解释和用途:

  1. int val

    • 含义:用于 SETVAL 操作,设置信号量的初始值。
    • 作用:当使用 SETVAL 操作时,可以通过 sem_arg.val 设置信号量的初始值。
  2. struct semid_ds *buf

    • 含义:用于 IPC_STATIPC_SET 操作,用于获取和设置信号量的属性。
    • 作用:当使用 IPC_STAT 操作时,可以将信号量的属性存储在 sem_arg.buf 中。当使用 IPC_SET 操作时,可以将要设置的属性存储在 sem_arg.buf 中。
  3. unsigned short *array

    • 含义:用于 GETALLSETALL 操作,用于获取和设置信号量集中所有信号量的值。
    • 作用:当使用 GETALL 操作时,可以将信号量集中所有信号量的值存储在 sem_arg.array 中。当使用 SETALL 操作时,可以将要设置的值存储在 sem_arg.array 中。
  4. struct seminfo *__buf

    • 含义:仅适用于 Linux 特定的 IPC_INFO 操作。
    • 作用:用于获取信号量相关的信息,这是一个 Linux 特定的功能。

总之,union semun 用于在 semctl 函数中指定参数,以根据不同的操作类型设置或获取信号量的不同属性。不同成员的使用取决于要执行的操作,以提供所需的信息。

2.常用信号

  1. SIGINT (2): 当用户按下 Ctrl+C 时发送给进程的信号,用于中断(中止)程序。

  2. SIGTERM (15): 请求终止进程的信号,通常由系统管理员或其他进程发送,进程可以捕获这个信号并做一些清理操作后退出。

  3. SIGQUIT (3): 类似于 SIGINT,但用户按下 Ctrl+\ 时发送。进程可以捕获这个信号,用于请求进程退出并生成核心转储文件。

  4. SIGHUP (1): 当终端关闭或连接断开时发送给进程的信号,通常用于通知进程重新加载配置或重新初始化。

  5. SIGKILL (9): 强制终止进程的信号,进程无法捕获或忽略,通常用于紧急情况下终止进程。

  6. SIGALRM (14): 由 alarm 函数设置的定时器到期时发送的信号,通常用于定时操作。

  7. SIGUSR1 (10)SIGUSR2 (12): 用户自定义的信号,进程可以捕获和处理,用于进程间通信或自定义操作。

  8. SIGCHLD (17): 子进程状态改变时发送给父进程的信号,父进程可以捕获并处理。

  9. SIGCONT (18): 继续执行停止的进程的信号,由 kill 命令发送。

  10. SIGSTOP (19): 停止进程的信号,进程无法捕获或忽略,通常由系统管理员使用。

  11. **SIG_IGN **: 是一个宏,表示忽略信号,在信号处理函数中,使用SIG_IGN表示将对应的信号忽略,需要注意的是,并不是所有信号都可以被忽略,某些关键性的信号,比如SIGKILL 和SIGSTOP都不能被忽略。

这些只是常见的信号,实际上有更多的信号在不同的操作系统中存在。信号用于进程间通信、控制和处理,可以用于中断进程、处理错误、同步进程等多种情况。

3.常见的标志和参数,以及它们的含义和用途

当使用 System V IPC(Inter-Process Communication)机制时,我们会经常看到一些标志或参数,如 IPC_CREAT0666 等。下面列出了一些常见的标志和参数,以及它们的含义和用途:

  1. IPC_CREAT:

    • 含义:用于创建一个新的 IPC 对象(如消息队列、信号量、共享内存)。
    • 作用:如果指定了这个标志,系统将尝试创建一个新的 IPC 对象。如果对象已经存在,则会返回现有对象的标识符。
    • 例子:semget(key, nsems, IPC_CREAT | 0666) 创建一个新的信号量集,如果已存在则获取现有信号量集。
  2. IPC_EXCL:

    • 含义:与 IPC_CREAT 一起使用时,确保创建一个新的 IPC 对象。如果对象已经存在,则创建失败。
    • 作用:避免意外重复创建相同的 IPC 对象。
    • 例子:semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666) 尝试创建一个新的信号量集,如果已存在则失败。
  3. IPC_NOWAIT:

    • 含义:用于在进行某些操作时不阻塞。如果指定了这个标志,函数会立即返回,不会等待条件满足。
    • 作用:可用于非阻塞地尝试获取锁或执行其他操作。
    • 例子:semop(semid, &sembuf, 1, IPC_NOWAIT) 非阻塞地执行信号量操作。
  4. 0666、0644 等:

    • 含义:指定权限(权限掩码)。
    • 作用:用于设置 IPC 对象的权限,规定谁能够访问和修改 IPC 对象。
    • 例子:semget(key, nsems, IPC_CREAT | 0666) 设置创建的信号量集的权限为读写。

这些标志和参数在创建和操作 IPC 对象时非常有用,它们决定了对象的创建、访问和修改权限,以及阻塞和非阻塞的操作方式。

4.常见命令(cmd)

当使用 System V IPC 机制时,我们会使用一些命令来控制和操作 IPC 对象,如获取状态、设置初始值等。下面列出了一些常见的命令,以及它们的含义和用途:

  1. IPC_STAT:

    • 含义:用于获取 IPC 对象的状态信息。
    • 作用:允许进程查询 IPC 对象的状态,如获取共享内存的大小、获取信号量集的属性等。
    • 例子:semctl(semid, 0, IPC_STAT, &sem_ds) 获取信号量集的状态信息。
  2. IPC_SET:

    • 含义:用于设置 IPC 对象的状态。
    • 作用:允许进程修改 IPC 对象的属性,如更改共享内存的权限、更改信号量集的大小等。
    • 例子:shmctl(shmid, IPC_SET, &shmid_ds) 设置共享内存的属性。
  3. IPC_RMID:

    • 含义:用于删除 IPC 对象。
    • 作用:允许进程删除一个已经不再需要的 IPC 对象,释放其占用的资源。
    • 例子:semctl(semid, 0, IPC_RMID) 删除信号量集。
  4. SETVAL:

    • 含义:用于设置 IPC 对象的某些属性值,如信号量的初始值。
    • 作用:初始化 IPC 对象的属性,例如,可以设置信号量集的初始值为某个特定值。
    • 例子:semctl(semid, semnum, SETVAL, sem_arg) 设置信号量的初始值。
  5. GETALL:

    • 含义:用于获取多个 IPC 对象的值。
    • 作用:从 IPC 对象中一次性获取多个值,如从信号量集中获取所有信号量的值。
    • 例子:semctl(semid, 0, GETALL, sem_array) 获取信号量集中所有信号量的值。
  6. SETALL:

    • 含义:用于设置多个 IPC 对象的值。
    • 作用:一次性设置多个 IPC 对象的属性,如将所有信号量的值设置为特定值。
    • 例子:semctl(semid, 0, SETALL, sem_array) 设置信号量集中所有信号量的值。

4.常用函数

  1. semget - 创建或获取信号量集

    int semget(key_t key, int nsems, int semflg);
    
    • 返回值: 成功时返回信号量标识符(非负整数),失败时返回 -1。
    • 作用: 用于创建一个新的信号量集或获取一个已存在的信号量集。
    • 常用参数:
      • key:用于标识信号量集的键值,通过 ftok 函数生成。
      • nsems:指定要创建的信号量数量。
      • semflg:标志位,可以使用 IPC_CREAT 表示创建信号量,还可以和其他标志位组合,如 0666 权限等。
  2. semctl - 控制信号量

    int semctl(int semid, int semnum, int cmd, ...);
    
    • 返回值: 成功时根据命令不同可能有不同的含义,失败时返回 -1。
    • 作用: 用于控制信号量,执行操作如获取/设置信号量的值、删除信号量等。
    • 常用参数:
      • semid:信号量标识符,由 semget 返回。
      • semnum:信号量在信号量集中的索引,通常为 0。
      • cmd:要执行的操作命令,如 IPC_STAT(获取信号量状态)、SETVAL(设置初始值)等。
      • 可变参数:取决于命令,例如在 SETVAL 命令中使用,表示要设置的值。
  3. semop - 执行信号量操作

    int semop(int semid, struct sembuf *sops, unsigned nsops);
    
    • 返回值: 成功时返回 0,失败时返回 -1。
    • 作用: 用于执行一组信号量操作,如等待信号量(P 操作)和释放信号量(V 操作)。
    • 常用参数:
      • semid:信号量标识符,由 semget 返回。
      • sops:指向 sembuf 结构体数组的指针,每个操作包括信号量编号、操作类型和操作标志。
      • nsops:要执行的操作数量。
  4. 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 函数中传递不同类型的参数,如设置信号量的初始值、获取信号量信息等。
  5. 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_UNDOSEM_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 成员来表示等待或释放资源。

  1. 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 触发的中断信号)的处理方式设置为忽略。你还可以使用其他的信号处理方式,如自定义的信号处理函数等。

  1. 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_handlersa_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;
}

解释和注释:

  1. semget(IPC_PRIVATE, 1, IPC_CREAT | 0666):创建一个只有一个信号量的信号量集。IPC_PRIVATE 生成一个新的唯一键值。如果创建失败,输出错误信息并退出。

  2. union semun sem_arg; sem_arg.val = 1;:定义一个联合体变量 sem_arg,用于后续设置信号量的初始值为 1。

  3. semctl(semid, 0, SETVAL, sem_arg):使用 semctl 函数将信号量的初始值设置为 1。

  4. struct sigaction act; act.sa_handler = SIG_IGN; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL);:设置信号处理函数,使得进程忽略 Ctrl+C(SIGINT)信号。

  5. printf("按下 Ctrl+C 不会中断程序。\n");:打印提示信息,说明按下 Ctrl+C 不会中断程序。

  6. struct sembuf sem_buf = {0, -1, 0};:定义一个 sembuf 结构体,其中 sem_num 是信号量索引,sem_op 是操作值(-1 表示执行 P 操作),sem_flg 是标志位(0 表示无特殊标志)。

  7. semop(semid, &sem_buf, 1);:执行信号量操作,尝试执行一个 P 操作,但实际上是一个占位操作。

  8. semctl(semid, 0, IPC_RMID):删除之前创建的信号量集。

总结信号量编程的通用步骤:

  1. 使用 semget 函数创建信号量集,设置标志和权限。
  2. 使用 semctl 函数初始化或设置信号量的值和属性。
  3. 使用 sigaction 函数设置信号处理函数,控制信号的行为。
  4. 执行信号量操作(P 操作或 V 操作)来控制资源的访问。
  5. 使用 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;
}

在这里插入图片描述


总结

信号量编程是一种在多进程/线程环境中实现进程同步、互斥和资源共享的编程技术。以下是关键要点的总结:

  1. 信号量: 信号量是一个计数器,用于控制多进程对共享资源的访问。它支持 P 操作(申请资源)和 V 操作(释放资源)。

  2. P 操作和 V 操作: P 操作用于等待资源,V 操作用于释放资源。这两者共同协调进程对资源的访问。

  3. 创建和初始化: 使用 semgetsemctl 函数创建和初始化信号量。可以设置初始值和属性。

  4. 资源同步: 信号量用于协调进程执行顺序,避免竞态条件。P 操作使进程等待,直到资源可用。

  5. 资源互斥: 信号量确保一次只有一个进程可以访问共享资源。V 操作允许其他进程获得资源。

  6. 资源共享: 信号量也用于控制多个进程/线程对共享资源的访问,确保资源正确分配和释放。

  7. 进程同步: 通过信号量可以实现进程之间的同步,确保它们在正确的时机执行。

  8. 应用场景: 适用于需要多个进程/线程协同工作、资源共享的情况,如控制文件访问、共享内存、网络资源等。

  9. 注意事项: 信号量编程需要小心设计,以避免死锁和资源泄漏。

  10. 步骤总结:

  • 创建信号量:使用 semget 函数创建信号量集。
  • 初始化信号量:使用 semctl 函数初始化信号量值和属性。
  • 执行操作:使用 semop 函数执行 P 操作和 V 操作。
  • 设置信号处理:使用 sigaction 函数设置信号处理函数,控制信号行为。
  • 删除信号量:使用 semctl 函数删除信号量集,释放资源。

综上所述,信号量编程是一种强大的并发编程技术,用于实现多进程/线程的同步、互斥和资源管理,确保程序在复杂并发环境下的正确性和稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值