有没有一种方法可以重用pthread?

5

我有一个被调用了数百万次的函数,这个函数的工作是多线程的。以下是该函数:

void functionCalledSoManyTimes()
{
  for (int i = 0; i < NUM_OF_THREADS; i++)
  {
    pthread_create(&threads[i], &attr, thread_work_function, (void *)&thread_data[i]);
  }
  // wait
}

每次调用函数时,我都会创建线程,并将每个线程的数据结构(在算法开始时设置一次)分配给thread_work_function进行使用。 thread_work_function 简单地处理一系列数组,而thread_data结构包含指向这些数组的指针以及每个线程负责的索引。
尽管以这种方式将算法多线程化使性能提高了20%以上,但我的分析表明,重复调用pthread_create会导致显着的开销。
我的问题是:有没有一种方法可以在不每次调用函数时调用pthread_create的情况下实现我的目标?
问题已解决。
谢谢大家,非常感谢你们的帮助! 我用你们的技巧写了一个解决方案,请参见此处

2
你需要了解线程池的概念。在这里,你有一组等待工作的线程池。你可以将工作安排在队列中,线程会被阻塞,然后一个线程会选择并执行这个工作。这是一个相当常见的概念,如果可能的话,可以从类似APR(Apache Portable Runtime)的东西中提取这个功能。 - Nim
2个回答

3

只需要启动一组固定的线程,并使用一种线程间通信系统(例如环形缓冲区)来传递要处理的数据。


2
优雅地解决这个问题并不容易。您可以为线程池使用静态存储,但是如果functionCalledSoManyTimes本身可以从多个线程调用,那么会发生什么情况?这不是一个好的设计。
我处理这种情况的方法是,在第一次调用时使用pthread_key_create创建一个线程局部存储键(使用pthread_once),并使用pthread_setspecific在给定线程中首次调用functionCalledSoManyTimes时将线程池存储在其中。您可以为pthread_key_create提供一个析构函数,该函数将在线程存在时被调用,然后该函数可以负责通过pthread_cancel或其他机制向工作线程发出终止信号。

1
有时候你可以将问题推到上层 - 要求调用functionCalledSoManyTimes的调用者传入一个由你提供的函数创建/销毁的线程池。如果调用者的代码类似于for (int i = 0; i < SOMANY; ++i) functionCalledSoManyTimes();,这个改变很容易实现;但如果该函数从许多不相关的地方调用,那么就不容易了;而且如果你想要隐藏它是多线程的事实,那么这个改变虽然容易,但是没有意义。 - Steve Jessop
这也是一个不错的解决方案,但我怀疑它通常不适用,特别是如果你想保持functionCalledSoManyTimes的实现不透明/封装。 - R.. GitHub STOP HELPING ICE
同意。我提到这个是因为我想在引入隐藏的共享状态之前将其排除在外,无论是静态的还是线程本地的。如果我失败了排除它,那就是一个奖励。另一个可能性是告诉调用者他们正在创建和传入的是ManyTimesFunctionOptimizer。它秘密地包含一个线程池,你的函数实现被封装起来,但是可以选择性地重新使用该对象以获得速度提升。该对象是否包含线程池或记忆化缓存(或两者皆有)对于调用者来说是不透明的。 - Steve Jessop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接