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

线程池触发竞态条件且子线程未执行问题求助

线程池代码问题解答

Q1:代码是否存在问题?执行时出现竞态条件

你的最小复现示例中输出重复数字,根本原因不是线程池内部的竞态,而是任务参数传递逻辑错误:
你在主线程循环中传递&idx作为任务参数,所有任务共享同一个idx的内存地址。主线程会快速递增idx,当子线程执行func读取该地址的值时,idx已经被主线程修改多次,甚至多个子线程可能同时读取到同一个被修改后的值,自然会出现重复输出。

解决参数传递问题的方案

为每个任务分配独立内存存储当前idx值,避免共享地址:

// 修改main中的循环逻辑
while (1) {
    int *num = malloc(sizeof(int));
    *num = idx;
    tp.add_job(func, num);
    idx++;
}

同时在任务函数中释放内存,避免泄漏:

void func(void* arg) {
    int num = *(int*)arg;
    printf("%d\n", num);
    free(arg); // 释放分配的内存
    usleep(100);
}

线程池自身的潜在问题

  • is_shutdown未声明为volatile,也无同步保护:主线程在析构时设置is_shutdown=1,子线程可能因CPU缓存优化看不到该修改,无法正确退出循环。建议改为volatile int is_shutdown,或访问时加互斥锁。
  • 析构函数存在时序问题:调用sem_post后直接销毁互斥锁和信号量,此时子线程可能仍在运行,会引发未定义行为。需等待所有子线程退出后再销毁同步原语(可通过原子变量统计活跃线程数、配合条件变量实现)。

Q2:主线程不加sleep()时子线程未执行的原因

这是Linux线程调度的正常现象:
你的主线程是无限循环的密集计算任务(不停调用add_job和递增idx),会持续占用CPU时间片。Ubuntu默认采用SCHED_OTHER普通分时调度策略,同优先级线程下,主线程未主动放弃CPU(如调用sleep、usleep等阻塞调用)时,子线程很难抢到调度时间片,看起来就像未执行。

验证方法:在主线程循环中加入usleep(1)这类微小延迟,主动让出CPU,子线程即可正常执行任务。


原线程池头文件(thread_pool.h)

//this is thread_pool.h
#ifndef _THREAD_POLL_H_
#define _THREAD_POLL_H_

#include <list>
#include <vector>
#include <unistd.h>
// #include "locker.h"
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <semaphore.h>

class thread_pool {
private:
    struct task {
        void (*fun)(void*);
        void* arg;
    };
private:
    int size;       //the num of working threads
    pthread_mutex_t lock;       //a mutex
    sem_t sem;    //semaphore to indicate the num of jobs
    std::list<task> tasks;
    std::vector<pthread_t> threads; 

    const int default_size = 16;
    int is_shutdown;
public:
    thread_pool();
    thread_pool(int num);
    ~thread_pool();
    void add_job(void (*fun)(void*), void* arg);
private:
    static void* work(void* arg);   //the working threads' call back
    void run();                     //the actual function that work() calls
};

#endif

原线程池实现(thread_pool.cpp)

//this is thread_pool.cpp
#include "thread_pool.h"


thread_pool::thread_pool(int num) : size(num), is_shutdown(0) {
    if (num <= 0) {
        fprintf(stderr, "the num of working threads is incorrect\n");
        exit(1);
    }
    pthread_mutex_init(&lock, NULL);
    sem_init(&sem, 0, 0);
    threads.resize(num);
    pthread_mutex_lock(&lock);
    for (int i = 0; i < num; i++) {
        pthread_create(&threads[i], NULL, work, this);
        // printf("thread %d is created\n", threads[i]);
        pthread_detach(threads[i]);
    }    
    pthread_mutex_unlock(&lock);
}

thread_pool::thread_pool() : thread_pool(default_size) {}

thread_pool::~thread_pool() {
    is_shutdown = 1;
    for (int i = 0; i < size; i++)
        sem_post(&sem);
    pthread_mutex_destroy(&lock);
    sem_destroy(&sem);
}

void* thread_pool::work(void* arg) {
    thread_pool* pool = (thread_pool*)arg;
    pool->run();
    return pool;
}

void thread_pool::run() {
    while (true) {
        sem_wait(&sem);
        if (is_shutdown) {
            break;
        }

        pthread_mutex_lock(&lock);
        if (tasks.empty()) {
            pthread_mutex_unlock(&lock);
            continue;
        }
        // printf("thread %d run\n", pthread_self());
        task tmp = tasks.front();
        tasks.pop_front();
        pthread_mutex_unlock(&lock);
        tmp.fun(tmp.arg);
    }
}

void thread_pool::add_job(void (*fun)(void*), void* arg) {
    pthread_mutex_lock(&lock);
    task tmp;
    tmp.fun = fun;
    tmp.arg = arg;
    tasks.push_back(tmp);
    sem_post(&sem);
    pthread_mutex_unlock(&lock);
}

原复现代码(main.cpp)

#include <stdio.h>
#include "thread_pool.h"

int idx = 0; 

void func(void* arg) {
    printf("%d\n", *(int*)arg);
    usleep(100);
}

int main() {
    thread_pool tp(8);
    while (1) {
        tp.add_job(func, (void*)&idx);
        idx++;
    }
} 

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 05:55:15