0

我是 Win32 中的多线程新手。我有一个信号量的任务。但我无法理解这一点。

假设我们有 20 个任务(每个任务与其他任务相同)。我们使用信号量然后有两种情况:

首先,应该有 20 个子线程,以便每个线程处理 1 个任务。

或者:

其次,会有 n 个子线程。当一个线程完成一个任务时,它会处理另一个任务吗?

我反驳的第二个问题是,我在 Win32(API) 中找不到任何 Semaphore 示例,但在 MSDN 中找到了 Consonle。

您能帮我完成“ 20 任务”并告诉我在 WinAPI 应用程序中编写信号量的说明(我应该在哪里放置 CreateSemaphore() 函数...)?

您的建议将不胜感激。

4

2 回答 2

2

您可以为每个任务启动一个线程,这是一种常见的方法,或者您可以使用一个“线程池”来重用线程。这取决于你。在这两种情况下,您可能会或可能不会使用信号量,区别仅在于您如何启动多个线程。

现在,关于您在哪里放置 CreateSemaphore() 函数的问题,您应该在开始任何其他线程之前调用它。原因是这些线程需要访问信号量,但如果它还不存在,它们就不能这样做。您当然可以将它传递给其他线程,但这又会给您带来如何在没有任何竞争条件的情况下安全地传递它的问题,这是信号量和其他同步原语要避免的事情。换句话说,你只会通过创造一个先有鸡还是先有蛋的问题来使事情复杂化。

请注意,如果这对您没有任何帮助,您或许应该提供更多信息。目标是什么?到目前为止,你自己做了什么?您在这里阅读的任何相关问题,但没有完全回答您的问题?

于 2013-06-15T12:44:31.933 回答
0

好吧,如果你被限制只使用信号量,你可以使用两个信号量来创建一个无界的生产者-消费者队列类,你可以用它来实现一个线程池。

您需要一个用于任务对象的“SimpleQueue”类。我假设您已经拥有一个,可以轻松构建一个或其他任何东西。

在您的“ProducerConsumerQueue”类的 ctor 中(或在 main() 中,或在返回 *ProducerConsumerQueue 结构的某些工厂函数中,无论您的语言有什么),创建一个 SimpleClass 和两个信号量。一个“QueueCount”信号量,初始化为 0,一个“QueueAccess”信号量,初始化为 1。

将 'push(*task)' 和 '*task pop()' 方法/memberFunctions/methods 添加到 ProducerConsumerQueue:

在 'push' 中,首先调用 QueueAccess 上的 'WaitForSingleObject()' API,然后将 *task 推送到 SimpleQueue,然后在 QueueAccess 上调用 ReleaseSemaphore() API。这会以线程安全的方式推送 *task。然后 QueueCount 上的 ReleaseSemaphore() - 这将发出任何等待线程的信号。

在 pop() 中,首先在 QueueCount 上调用 'WaitForSingleObject()' API - 这确保任何调用消费者线程都必须等待,直到队列中有一个 *task。然后在 QueueAccess 上调用 'WaitForSingleObject()' API,然后从 SimpleQueue 中弹出任务,然后在 QueueAccess 上调用 ReleaseSemaphore() API 并返回任务- 这个线程安全地将 *task 出列。

创建 ProducerConsumerQueue 后,创建一些线程来运行任务。在 CreateThread() 中,传递相同的 *ProducerConsumerQueue 作为 'auxiliary' *void 参数。

在线程函数中,将 *void 转换回 *ProducerConsumerQueue,然后永远循环,调用 pop(),然后运行返回的任务。

好的,你的线程池现在已经准备好做一些事情了。如果要运行 20 个任务,请在循环中创建它们并将它们推送到 ProducerConsumerQueue。然后线程将全部运行它们。

您可以在池中创建任意数量的线程(在合理范围内)。对于 CPU 密集型任务,与内核一样多的线程是合理的。如果任务进行阻塞调用,您可能希望创建更多线程以获得最快的整体吞吐量。

一个有用的增强是在接收到每个任务后检查线程函数循环中的“null”,如果它为null,则清理退出线程,从而终止它。这允许通过排队空值轻松终止线程,从而更容易关闭线程池(如果需要),并且还可以在运行时控制池中的线程数。

于 2013-06-15T12:50:59.567 回答