You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于在main()外及其他.c文件中使用mutexes与semaphores的初始化销毁位置咨询

关于互斥锁与信号量的初始化/销毁时机问题

首先明确:绝对不能在每个自定义函数内重复调用初始化和销毁函数,这种写法完全错误,原因如下:

  1. 重复初始化已处于初始化状态的互斥锁/信号量属于未定义行为,可能直接导致程序崩溃或死锁。
  2. 销毁同步对象后,后续再对其进行加锁/等待操作同样是未定义行为,会引发不可预测的问题。
  3. 每个函数内初始化的同步对象是独立实例,根本无法实现跨线程的同步效果。

正确的调用时机与方式

互斥锁和信号量是全局生命周期的同步工具,必须遵循「所有线程启动前初始化,所有线程结束后销毁」的原则,具体实现分两种场景:

场景1:动态初始化(推荐,兼容性更强)

在自定义函数所在的.c文件中定义全局同步对象,再提供专门的初始化/销毁函数,由main()函数在合适时机调用:

// custom.c
#include <pthread.h>
#include <semaphore.h>

// 全局同步对象,供所有自定义函数共享
pthread_mutex_t g_sync_mutex;
sem_t g_sync_sem;

// 初始化同步对象的函数,需在所有线程创建前调用
void sync_init() {
    // 初始化互斥锁,使用默认属性
    pthread_mutex_init(&g_sync_mutex, NULL);
    // 初始化信号量:第二个参数0表示线程间共享,第三个参数是初始值
    sem_init(&g_sync_sem, 0, 1);
}

// 销毁同步对象的函数,需在所有线程结束后调用
void sync_destroy() {
    pthread_mutex_destroy(&g_sync_mutex);
    sem_destroy(&g_sync_sem);
}

// 自定义函数,使用同步对象
void my_custom_func() {
    pthread_mutex_lock(&g_sync_mutex);
    // 临界区代码:需要互斥访问的逻辑
    pthread_mutex_unlock(&g_sync_mutex);

    sem_wait(&g_sync_sem);
    // 信号量保护的代码:控制并发访问数量的逻辑
    sem_post(&g_sync_sem);
}

对应的main()函数逻辑:

// main.c
#include "custom.h"
#include <pthread.h>

int main() {
    // 先初始化所有同步对象
    sync_init();

    // 创建工作线程,线程执行逻辑中会调用my_custom_func等函数
    pthread_t thread1, thread2;
    pthread_create(&thread1, NULL, (void*)my_custom_func, NULL);
    pthread_create(&thread2, NULL, (void*)my_custom_func, NULL);

    // 等待所有线程执行完毕
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    // 最后销毁同步对象
    sync_destroy();
    return 0;
}

场景2:静态初始化(仅互斥锁适用)

互斥锁支持通过宏PTHREAD_MUTEX_INITIALIZER进行静态初始化,无需调用pthread_mutex_init,但销毁仍需在所有线程结束后执行:

// custom.c
#include <pthread.h>
#include <semaphore.h>

// 静态初始化互斥锁
pthread_mutex_t g_sync_mutex = PTHREAD_MUTEX_INITIALIZER;
// 信号量仍需动态初始化
sem_t g_sync_sem;

void sync_init() {
    sem_init(&g_sync_sem, 0, 1);
}

void sync_destroy() {
    pthread_mutex_destroy(&g_sync_mutex);
    sem_destroy(&g_sync_sem);
}

// 自定义函数逻辑同上

补充说明

  • 如果你尝试在.c文件顶部直接调用初始化函数(比如在全局作用域写pthread_mutex_init(&g_mutex, NULL);),这是不允许的——全局作用域只能执行变量初始化,不能直接调用函数(C标准不支持)。
  • 销毁操作必须等待所有使用同步对象的线程完全退出后再执行,否则会导致线程操作已销毁的对象,引发异常。

内容的提问来源于stack exchange,提问作者DualisticDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 08:35:34