小工具知识网

当前位置: 首页 > 行业知识 > 【探索Linux】—— 强大的命令行工具 P.22(POSIX信号量)

行业知识

【探索Linux】—— 强大的命令行工具 P.22(POSIX信号量)

2026-11-05 04:16:43 来源:互联网转载

阅读导航

  • 引言
  • 一、POSIX信号量的基本概念
  • 二、信号量的相关操作
    • 1 . 初始化信号量sem_init ( )
      • (1)原型
      • (2)参数
      • (3)返回值
      • (4)示例代码
      • 2 . 等待信号量
        • (1)sem_wait ( )
          • - 原型
          • - 参数
          • - 返回值
          • (2)sem_trywait ( )
            • - 原型
            • - 参数
            • - 返回值
            • (3)sem_timedwait
              • - 原型
              • - 参数
              • - 返回值
              • (4)示例代码
              • 3 . 发布信号量sem_post( )
                • (1)原型
                • (2)参数
                • (3)返回值
                • (4)示例代码
                • 注意事项
                • 4 . 销毁信号量sem_destroy()
                  • (1)原型
                  • (2)参数
                  • (3)返回值
                  • (4)示例代码
                  • 三、 使用场景与注意事项
                  • ���馨提示

                    引言

                    在上一篇文章中,我们深入探讨了多线程编程的核心概念,包括线程同步、条件变量以及线程安全等关键技术,为读者揭示了并发编程的复杂性及其解决方案。这些概念和技术是实现高效、稳定并发应用程序的基础。继续在并发编程的旅途上前进,本篇文章将引导我们走进Linux操作系统下的另一个重要概念——POSIX信号量(Semaphore)。

                    POSIX信号量是一种用于进程或线程间同步的机制,它提供了一种控制资源访问的方法,确保在任何时刻只有特定数量的线程可以访问特定的资源。这在处理资源共享问题时尤其重要,比如,在操作系统、数据库管理系统等领域,正确的使用信号量可以有效避免***锁和竞态条件,保证系统的稳定运行。

                    随着并发编程的普及,掌握各种同步机制成为每位开发者的必备技能。POSIX信号量作为其中的重要组成部分,其重要性不言而喻。让我们一起深入探索POSIX信号量,解锁并发编程的新技能。

                    一、POSIX信号量的基本概念

                    POSIX信号量是一种在POSIX-compliant系统(如Linux)中实现的线程或进程间同步机制。它提供了一组标准化的API,用于控制对共享资源的访问。信号量本质上是一个计数器,用于表示可用资源的数量。它支持两个基本操作:等待(wait)和信号(signal),在不同的文献中,这两个操作也被称为P(Proberen,尝试)和V(Verhogen,增加)操作。

                    二、信号量的相关操作

                    ⭕POSIX信号量定义在头文件中,主要包括以下几个函数

                    1 . 初始化信号量sem_init ( )

                    初始化:在使用信号量之前,必须先对其进行初始化,设定信号量的初始值,即可用资源的数量。

                    (1)原型

                    int sem_init(sem_t *sem, int pshared, unsigned int value);

                    (2)参数

                    • sem:指向信号量对象的指针。
                    • pshared:此参数指示信号量是在进程间共享还是仅限于线程间的共享。如果pshared的值为0,则信号量仅在同一进程的线程间共享;如果pshared的值非0,则信号量可以在多个进程间共享。
                    • value:用于指定信号量的初始值。

                      (3)返回值

                      • 成功时返回0。
                      • 失败时返回-1,并设置errno以指示错误原因。

                        (4)示例代码

                        下面是一个使用sem_init初始化信号量的简单示例:

                        #include #include #include sem_t sem;void* thread_function(void* arg) {    // 等待信号量    sem_wait(&sem);    printf("Entered..\n");    // 临界区代码...    printf("Exiting..\n");    // 释放信号量    sem_post(&sem);}int main() {    // 初始化信号量,初始值设为1    if (sem_init(&sem, 0, 1) != 0) {        perror("sem_init");        return 1;    }    pthread_t t1, t2;    // 创建两个线程    pthread_create(&t1, NULL, thread_function, NULL);    pthread_create(&t2, NULL, thread_function, NULL);    // 等待线程结束    pthread_join(t1, NULL);    pthread_join(t2, NULL);    // 销毁信号量    sem_destroy(&sem);    return 0;}

                        在这个示例中,我们创建了一个初始值为1的信号量,这意味着它可以被一个线程获取,从而进入临界区。当信号量的值为0时,其他试图获取该信号量的线程将会阻塞,直到信号量的值再次变为正数。通过调用sem_wait和sem_post函数,线程在进入和退出临界区时分别等待和释放信号量,从而实现了线程间的同步。

                        2 . 等待信号量

                        等待(P操作):当线程尝试获取一个资源时,会执行等待操作。如果信号量的值大于0,表示有资源可用,它就会减1并继续执行。如果信号量的值为0,表示没有可用资源,执行等待操作的线程将被阻塞,直到信号量的值变为大于0。

                        (1)sem_wait ( )

                        sem_wait 函数用于等待信号量。如果信号量的值大于0,该函数会将它减1并立即返回,让调用线程继续执行。如果信号量的值为0,调用线程将阻塞,直到信号量的值变为大于0。

                        - 原型
                        int sem_wait(sem_t *sem);
                        - 参数
                        • sem:指向信号量对象的指针。
                          - 返回值
                          • 成功时返回0。
                          • 失败时返回-1,并设置errno以指示错误原因。

                            (2)sem_trywait ( )

                            sem_trywait 函数尝试等待信号量,但与sem_wait不同的是,如果信号量的值为0,sem_trywait不会阻塞调用线程,而是立即返回一个错误。

                            - 原型
                            int sem_trywait(sem_t *sem);
                            - 参数
                            • sem:指向信号量对象的指针。
                              - 返回值
                              • 成功时返回0。
                              • 如果信号量的值为0,则返回-1,并设置errno为EAGAIN,表示没有获取到信号量。

                                (3)sem_timedwait

                                sem_timedwait 函数也用于等待信号量,但它允许指定一个超时时间。如果在指定的时间内信号量没有变为可用状态,函数将返回一个错误。

                                - 原型
                                int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
                                - 参数
                                • sem:指向信号量对象的指针。
                                • abs_timeout:指向timespec结构的指针,该结构指定了一个绝对超时时间。这个时间是从Epoch(1970-01-01 00:00:00 UTC)开始计算的。
                                  - 返回值
                                  • 成功时返回0。
                                  • 如果在指定时间内未能获取信号量,则返回-1,并设置errno为ETIMEDOUT。

                                    (4)示例代码

                                    下面是一个使用sem_wait等待信号量的简单示例:

                                    #include #include #include sem_t sem;void* thread_function(void* arg) {    // 等待信号量    sem_wait(&sem);    printf("Entered..\n");    // 模拟临界区代码    sleep(1);    printf("Exiting..\n");    // 释放信号量    sem_post(&sem);}int main() {    // 初始化信号量,初始值设为1    if (sem_init(&sem, 0, 1) != 0) {        perror("sem_init");        return 1;    }    pthread_t t1, t2;    // 创建两个线程    pthread_create(&t1, NULL, thread_function, NULL);    pthread_create(&t2, NULL, thread_function, NULL);    // 等待线程结束    pthread_join(t1, NULL);    pthread_join(t2, NULL);    // 销毁信号量    sem_destroy(&sem);    return 0;}

                                    在这个示例中,sem_wait被用于确保在任何时刻只有一个线程可以进入临界区执行。这是通过在进入临界区之前调用sem_wait来实现的,它会等待信号量变为可用(即信号量的值大于0)。成功进入临界区的线程在离开时通过调用sem_post来增加信号量的值,从而可能允许其他等待中的线程进入临界区。

                                    3 . 发布信号量sem_post( )

                                    信号(V操作):当线程释放一个资源时,会执行信号操作。信号操作会将信号量的值加1。如果有其他线程因等待该信号量而被阻塞,其中一个线程将被唤醒,以便它可以获取资源。

                                    sem_post 函数用于增加信号量的值。当信号量的值从0变为正数时,如果有线程因调用 sem_wait 而阻塞在该信号量上,那么其中一个线程将被唤醒(即解除阻塞状态并获得信号量)。

                                    (1)原型

                                    int sem_post(sem_t *sem);

                                    (2)参数

                                    • sem:指向信号量对象的指针。

                                      (3)返回值

                                      • 成功时返回0。
                                      • 失败时返回-1,并设置errno以指示错误原因。

                                        (4)示例代码

                                        以下是一个使用 sem_post 来发布(释放)信号量的简单示例,它演示了如何在一个线程中使用 sem_post 来允许另一个线程继续执行。

                                        #include #include #include sem_t sem;void* thread_function(void* arg) {    printf("Thread waiting for the semaphore...\n");    sem_wait(&sem); // 等待信号量    printf("Semaphore acquired by thread.\n");    // 执行一些操作...    sleep(1); // 模拟耗时操作    printf("Thread releasing the semaphore.\n");    sem_post(&sem); // 释放信号量}int main() {    // 初始化信号量,初始值设为0    if (sem_init(&sem, 0, 0) != 0) {        perror("sem_init failed");        return 1;    }    pthread_t t1;    pthread_create(&t1, NULL, thread_function, NULL);    printf("Main thread sleeping for 2 seconds...\n");    sleep(2); // 让线程有足够的时间进入等待状态    printf("Main thread posting the semaphore.\n");    sem_post(&sem); // 主线程释放信号量,允许子线程继续执行    pthread_join(t1, NULL); // 等待子线程结束    sem_destroy(&sem); // 销毁信号量    return 0;}

                                        在这个示例中,主线程初始化一个信号量并创建一个工作线程,然后休眠2秒钟。工作线程启动后会尝试通过调用 sem_wait 获取信号量,但由于信号量的初始值被设置为0,所以它将被阻塞。主线程在休眠结束后通过调用 sem_post 增加信号量的值,这导致阻塞的工作线程被唤醒并继续执行。

                                        注意事项

                                        • 使用 sem_post 时,应确保信号量已经通过 sem_init 或其他方式正确初始化。
                                        • sem_post 可以在任何时候被调用,不仅限于信号量的持有者线程。这意味着,即使一个线程没有通过 sem_wait 获取信号量,它也可以调用 sem_post 来增加信号量的值。
                                        • 在多线程程序中合理使用信号量,可以有效地控制线程间的同步和互斥,但需要注意避免***锁和竞争条件。

                                          4 . 销毁信号量sem_destroy()

                                          在使用POSIX信号量进行线程同步和互斥操作后,正确地销毁信号量是非常重要的。这不仅有助于释放系统资源,还可以避免资源泄漏。POSIX提供了sem_destroy函数来销毁信号量。

                                          sem_destroy函数用于销毁信号量,释放与之关联的资源。一旦信号量被销毁,它就不能再被使用,除非再次被初始化。

                                          (1)原型

                                          int sem_destroy(sem_t *sem);

                                          (2)参数

                                          • sem:指向信号量对象的指针。

                                            (3)返回值

                                            • 成功时返回0。
                                            • 失败时返回-1,并设置errno以指示错误原因。

                                              (4)示例代码

                                              以下是一个简单的示例,演示了如何创建、使用和销毁一个信号量:

                                              #include #include #include sem_t sem;void* thread_function(void* arg) {    sem_wait(&sem); // 等待信号量    printf("Thread entered critical section.\n");    // 执行临界区代码...    sleep(1); // 模拟耗时操作    printf("Thread leaving critical section.\n");    sem_post(&sem); // 释放信号量}int main() {    // 初始化信号量,初始值设为1    if (sem_init(&sem, 0, 1) != 0) {        perror("sem_init failed");        return 1;    }    pthread_t t1, t2;    pthread_create(&t1, NULL, thread_function, NULL);    pthread_create(&t2, NULL, thread_function, NULL);    // 等待线程完成    pthread_join(t1, NULL);    pthread_join(t2, NULL);    // 销毁信号量    if (sem_destroy(&sem) != 0) {        perror("sem_destroy failed");    }    return 0;}

                                              在这个示例中,我们创建了一个初始值为1的信号量,允许两个线程依次进入临界区。在线程执行完毕后,我们通过调用sem_destroy来销毁信号量,以确保程序优雅地释放了所有分配的资源。

                                              三、 使用场景与注意事项

                                              POSIX信号量广泛用于多线程和多进程环境中,以实现对共享资源的同步访问控制。在设计并发程序时,正确使用信号量是保证数据一致性和系统稳定性的关键。

                                              在使用POSIX信号量时,需要注意以下几点:

                                              • 确保在适当的时候初始化和销毁信号量。
                                              • 避免***锁,确保每个等待信号量的线程最终都能够继续执行。
                                              • 谨慎处理信号量操作可能失败的情况,特别是sem_wait可能由于中断而提前返回。

                                                通过合理使用POSIX信号量,开发者可以有效地解决多线程编程中的同步和互斥问题,提高程序的稳定性和效率。

                                                温馨提示

                                                感谢您对博主文章的关注与支持!如果您喜欢这篇文章,可以点赞、评论和分享给您的同学,这将对我提供巨大的鼓励和支持。另外,我计划在未来的更新中持续探讨与本文相关的内容。我会为您带来更多关于Linux以及C++编程技术问题的深入解析、应用案例和趣味玩法等。如果感兴趣的话可以关注博主的更新,不要错过任何精彩内容!

                                                再次感谢您的支持和关注。我们期待与您建立更紧密的互动,共同探索Linux、C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!

上一篇:newyork7am怎么读?

下一篇:美团外卖退款申请详解教程