C pthreads分批运行

时间:2011-08-24 03:54:27

标签: c concurrency pthreads

我有1000-10000个职位的名单。它存储在简单的char数组中。我需要尽快完成清单上的工作。

我想随时运行10个线程。如何在完成上一个线程之后立即(或几乎立即)运行新线程?

#define THREADS_LIMIT 10
const char * const jobs[]= { "data1", .... }
...
for (i = 0; i < THREADS_LIMIT; ++i)
{
// run first 10 threads
}

如何在上一次完成后启动线程?我可以运行10个线程,然后等待所有的线程完成,然后运行下一个10.但是有更有效的方法吗?

4 个答案:

答案 0 :(得分:5)

不要停止任何线程。只需让每个线程移动到下一个工作,而不是销毁它并创建一个新工作;当没有更多工作时,它们会终止。现在你的主程序只是启动THREAD_LIMIT线程,然后pthread_join全部启动。

答案 1 :(得分:1)

您可能会考虑的一件事是拥有一个线程安全的作业队列,每个线程可以从中拉出工作,直到没有剩余工作为止。然后启动但是许多线程是合适的,让它们全部工作,直到没有更多的工作。类似的东西:

#define THREADS_LIMIT 10

static pthread_mutex_t job_mutex = PTHREAD_MUTEX_INITIALIZER;
static const char * const jobs[]= { "data1", .... };

char const* get_job(void) 
{
    pthread_mutex_lock( &job_mutex);

    static char const* next_job = jobs;
    static char const* jobs_end = jobs + (sizeof(jobs)/sizeof(jobs[0]));

    char const* result = NULL;

    if (next_job != jobs_end) {
        result = next_job++;
    }

    pthread_mutex_unlock( &job_mutex);

    return result;
}



...
for (i = 0; i < THREADS_LIMIT; ++i)
{
// run first 10 threads
}


void* thread_fun( void* arg)
{
    for (char const* my_job = get_job(); my_job != NULL; my_job = get_job()) {
        // work on the job *my_job
    }

    return 0;
}

请注意,如果您的作业是CPU密集型的,那么您应该将它们的数量限制为机器所具有的CPU核心数。不止于此,他们将互相争夺CPU时间。

但是,如果您希望灵活地使作业队列动态化(因此可以在线程正在工作时将作业添加到队列中),则复杂性会增加。它只是增长一点,以保持添加/删除逻辑线程安全。但是为了确保仍然存在处理作业队列的线程,它会增长很多 - 例如,你必须确保没有竞争条件你认为还有一个或多个线程来处理队列,但这些线程实际上即将结束自己而不再检查作业队列。 当然,在成本上存储作业的方式会更加复杂,您可以对其进行扩展,以便作业队列可以添加项目

答案 2 :(得分:0)

您肯定需要一个线程池,您不希望为每个任务启动和停止线程。

主要的设计问题是如何将任务分发到池中,这些问题可以通过像0mq这样的中间件包简化,以便在调度程序和工作程序之间执行无锁IPC。

如果作业列表是硬编码的,那么您可以静态地分割工作负载,并说给每个线程一个索引进入作业队列并让它们迭代直到完成。

答案 3 :(得分:0)

最好的方法(在我看来)是创建一个包含作业的队列,然后启动十个线程,这些线程只是从队列中读取下一个作业并进行处理。

这具有最小的线程创建/销毁开销以及线程之间的工作负载自动平衡的优点。通过这种方式,我的意思是获得快速工作的线程会自动获得更多工作。

然后,在这10,000个作业结束时,放置10个关闭作业,这将导致工作线程退出,然后等待它们。

整个计划如下:

main thread:
    create a queue
    do ten times:
        start a worker thread
    do ten thousand times:
        add normal job to queue
    do ten times:
        add shutdown job to queue
    wait for all workers to finish
    exit

worker thread:
    while true:
        get job from queue
        if job is shutdown job:
            exit
        process job

显然,需要使用互斥锁来保护对队列的访问,以避免竞争条件。


你需要记住一件事。如果任务是CPU密集型的,那么拥有比可用执行单元(CPU或内核或其他任何东西)更多的线程,您将无法获得任何实际好处。

例如,如果您只有一个核心,那么最快的方法就是根本不使用线程。在这样的CPU密集型任务中使用线程实际上可能更慢,因为你引入了任务切换的开销。