我是Win32中Multithread的新手。我和Semaphore有一个任务。但我无法理解这一点。
假设我们有20个任务(每个任务与其他任务相同)。我们使用信号量然后有两种情况:
首先,应该有20个子线程,以便每个线程处理1个任务。
或者:
其次,会有n个童线。当一个线程完成一个任务时,它会处理另一个任务吗?
我反驳的第二个问题是我在Win32(API)中找不到Semaphore的任何样本,而是在MSDN中找到的Consonle。
你能帮我解决“ 20任务”并告诉我在WinAPI应用程序中编写信号量的说明(我应该在哪里放置CreateSemaphore()函数......)?
您的建议将不胜感激。
答案 0 :(得分:2)
您可以为每个任务启动一个线程,这是一种常见的方法,或者您可以使用“线程池”来重用线程。这取决于你。在这两种情况下,您可能使用或不使用信号量,区别仅在于您启动多个线程的方式。
现在,关于你在哪里放置CreateSemaphore()函数,你应该在开始任何进一步的线程之前调用它。原因是这些线程需要访问信号量,但如果它还不存在则不能这样做。你当然可以将它传递给其他线程,但这又会给你一个问题,即如何在没有任何竞争条件的情况下安全地传递它,这是信号量和其他同步原语可以避免的。换句话说,你只会通过创造一个鸡与蛋的问题来复杂化。
请注意,如果这对您没有任何帮助,您应该提供更多信息。目标是什么?到目前为止你自己做了什么?这里有任何相关问题,但是你没有完全呈现问题的答案吗?
答案 1 :(得分:0)
好吧,如果你只使用信号量,你可以使用两个信号量来创建一个可以用来实现线程池的无界生成者 - 消费者队列类。
您需要一个用于任务对象的'SimpleQueue'类。我假设你已经有一个,可以轻松地建立一个或其他。
在'ProducerConsumerQueue'类的ctor中,(或在main()中,或在返回* ProducerConsumerQueue结构的某个工厂函数中,无论您的语言是什么),创建一个SimpleClass和两个信号量。一个'QueueCount'信号量,初始化为0,一个'QueueAccess'信号量,初始化为1。
将'push(* task)'和'* task pop()'方法/ memberFunctions / methods添加到ProducerConsumerQueue:
在'push'中,首先在QueueAccess上调用'WaitForSingleObject()'API,然后将*任务推送到SimpleQueue,然后推送到QueueAccess上的ReleaseSemaphore()API。这以线程安全的方式推送*任务。然后在QueueCount上发布ReleaseSemaphore() - 这将发出任何等待线程的信号。
在pop()中,首先在QueueCount上调用'WaitForSingleObject()'API - 这可以确保任何调用的消费者线程都必须等到队列中有*任务。然后在QueueAccess上调用'WaitForSingleObject()'API,然后从SimpleQueue中弹出任务,然后在QueueAccess上弹出ReleaseSemaphore()API并返回任务 - 这个线程安全地使*任务出列。
创建ProducerConsumerQueue后,创建一些线程来运行任务。在CreateThread()中,将相同的* ProducerConsumerQueue作为'auxiliary'* void参数传递。
在thread函数中,将* void转换回* ProducerConsumerQueue,然后只需循环遍历,调用pop()然后运行返回的任务。
好的,您的线程池现在已准备就绪。如果要运行20个任务,请在循环中创建它们并将它们推送到ProducerConsumerQueue。然后线程将全部运行它们。
您可以在池中创建任意数量的线程(在合理范围内)。对于CPU密集型的任务,许多线程作为核心是合理的。如果任务进行阻塞调用,您可能需要创建更多线程以获得最快的整体吞吐量。
一个有用的增强功能是在收到每个任务后检查线程函数循环中的“null”,如果为null,则清除线程的退出,从而终止它。这允许通过排队空值来轻松终止线程,从而更容易关闭线程池(如果需要),并且还可以在运行时控制池中的线程数。