SetThreadAffinityMask的汇集线程

时间:2010-11-24 14:44:17

标签: c++ windows multithreading threadpool

我想知道是否可以设置从线程池获取的线程的处理器关联。更具体地说,线程是通过使用TimerQueue API获得的,我用它来实现周期性任务。

作为旁注:我发现TimerQueues是实现周期性任务的最简单方法,但由于这些通常是长期任务,因此为此目的使用专用线程可能更合适吗?此外,预计需要使用诸如semapores和互斥体之类的同步原语来同步各种周期性任务。汇集的线程是否适合这些?

谢谢!

EDIT1:正如Leo指出的那样,上述问题实际上只是两个松散相关的问题。第一个与池化线程的处理器关联性有关。第二个问题涉及从TimerQueue API获得的池化线程在同步对象中的行为是否与手动创建的线程一样。我将把第二个问题作为一个单独的主题。

2 个答案:

答案 0 :(得分:2)

如果这样做,请确保每次将线程释放回池时返回的内容。由于您不拥有这些线程,因此使用它们的其他代码可能有其他要求/假设。

你确定你真的需要这样做吗?需要设置处理器亲和力是非常非常罕见的。 (我认为我不需要在我写过的任何内容中做到这一点。)

线程关联可能意味着两件完全不同的事情。(感谢bk1e对我原来的答案的评论,指出了这一点。我没有意识到自己。)

  1. 我称之为处理器关联性:线程需要在同一处理器上一致运行。这就是SetThreadAffinityMask处理的内容,代码很少关心它。 (通常是由于高性能代码中的CPU缓存等非常低级别的问题。通常操作系统会尽力将线程保持在同一个CPU上,并且通常会适得其反,迫使它不这样做。)

  2. 我称之为线程亲和力:对象使用线程本地存储(或者某些其他状态与他们访问的线程相关联),如果一个序列动作不是在同一个线程上完成的。

  3. 从您的问题来看,您可能会将#1与#2混淆。在您的回调正在运行时,线程本身不会更改 。当一个线程正在运行时,它可能会在CPU之间跳转,但这是正常的,而不是你必须担心的事情(除非是非常特殊的情况)。

    互斥体,信号量等不关心线程是否在CPU之间跳转。

    如果线程池多次执行回调,则(通知池的使用方式)通常不保证每次都使用相同的线程。即你的回调可能会在线程之间跳转,但不会在它运行的中间跳转;它可能只会在每次运行时更改线程。

    如果您的回调代码在一个线程上运行,然后仍然认为它在这些对象上持有锁,则会在另一个线程上再次运行某些同步对象 。 (第一个线程仍将保持锁定,而不是第二个线程,尽管它取决于您使用哪种同步对象。有些人不关心。)但这不是#1;这是#2,而不是你使用SetThreadAffinityMask来处理的事情。

    例如,Mutexes(CreateMutex)由一个线程拥有。如果在线程A上获取互斥锁,则尝试获取互斥锁的任何其他线程将阻塞,直到您在线程A上释放互斥锁。(线程释放它不拥有的互斥锁也是错误。)所以如果你的回调获得了一个互斥,然后退出,然后又在另一个线程上运行并从那里释放互斥,这将是错误的。

    另一方面,Event(CreateEvent)并不关心哪些线程创建,发送或销毁它。你可以在一个线程上发出一个事件的信号,然后在另一个线程上重置它,这很好(正常,实际上)。

    在两次单独的回调运行之间保持一个同步对象也是很少见的(这会引发死锁,尽管有些情况下你可以合法地想要/做这样的事情)。但是,如果您创建了(例如)一个公寓线程的COM对象,那么您只希望从一个特定的线程访问它。

答案 1 :(得分:0)

你不应该。你只应该将那个线程用于当前正在运行的处理器上的工作。除了显而易见的低效率之外,线程池可能会在您完成后立即销毁每个线程,并为您的下一个作业创建一个新线程。亲密面具不会在实践中很快消失,但如果它们随机消失则更难调试。