使用boost::condition\u变量进行线程同步 我正在做C++多线程的实验,我不知道如何解决一个问题。假设我们有线程池,它使用现有线程处理用户请求,并在没有可用线程的情况下创建新线程。我已经创建了命令队列线程安全类,它有push和pop方法。pop在队列为空时等待,并仅在命令可用或发生超时时返回。现在是实现线程池的时候了。这个想法是让空闲线程睡眠一段时间,如果在这段时间后没有什么事情可做,就杀死线程。这里是实现 command_queue::handler_t handler; while (handler = tasks.pop(timeout)) { handler(); }

使用boost::condition\u变量进行线程同步 我正在做C++多线程的实验,我不知道如何解决一个问题。假设我们有线程池,它使用现有线程处理用户请求,并在没有可用线程的情况下创建新线程。我已经创建了命令队列线程安全类,它有push和pop方法。pop在队列为空时等待,并仅在命令可用或发生超时时返回。现在是实现线程池的时候了。这个想法是让空闲线程睡眠一段时间,如果在这段时间后没有什么事情可做,就杀死线程。这里是实现 command_queue::handler_t handler; while (handler = tasks.pop(timeout)) { handler(); },c++,boost,threadpool,C++,Boost,Threadpool,这里,如果发生超时,我们将退出线程过程。这很好,但新线程的创建存在问题。假设我们已经有2个线程处理用户请求,它们目前正在工作,但我们需要异步执行其他一些操作。 我们叫 应该启动新线程,因为没有可用的空闲线程。当线程可用时,它调用timed\u waiton条件变量,因此检查是否有线程在等待 if (thread_are_free_threads) // ??? condition.notify_one(); else create_thread(thread_proc); 但是如何

这里,如果发生超时,我们将退出线程过程。这很好,但新线程的创建存在问题。假设我们已经有2个线程处理用户请求,它们目前正在工作,但我们需要异步执行其他一些操作。 我们叫

应该启动新线程,因为没有可用的空闲线程。当线程可用时,它调用
timed\u wait
on条件变量,因此检查是否有线程在等待

if (thread_are_free_threads) // ???
   condition.notify_one();
else
   create_thread(thread_proc);
但是如何检查呢?文档中说,如果没有等待的线程,就什么也不做。如果我能检查一下它是否没有任何作用,那将是一个解决办法

if (!condition.notify_one()) // nobody was notified
   create_thread(thread_proc);
据我所知,没有办法核实这一点


谢谢您的回答。

您需要创建另一个变量(可能是一个信号量),该变量知道有多少线程正在运行,然后您可以在调用notify之前检查该变量并创建一个新线程(如果需要)


另一个更好的选择是,线程超时时不要退出。他们应该活着等待通知。不要在通知超时时退出,而是检查一个变量以查看程序是否仍在运行或是否正在“关闭”,如果程序仍在运行,则再次开始等待。

更典型的线程池如下所示:

Pool::Pool()
{
    runningThreads = 0;
    actualThreads  = 0;
    finished       = false;
    jobQue.Init();

    mutex.Init();
    conditionVariable.Init();

    for(int loop=0; loop < threadCount; ++loop) { startThread(threadroutine); }
}

Pool::threadroutine()
{

    {
        // Extra code to count threads sp we can add more if required.
        RAIILocker doLock(mutex);
        ++ actualThreads;
        ++ runningThreads;
    }
    while(!finished)
    {
         Job job;
         {
             RAIILocker doLock(mutex);

             while(jobQue.empty())
             {
                 // This is the key.
                 // Here the thread is suspended (using zero resources)
                 // until some other thread calls the notify_one on the
                 // conditionVariable. At this point exactly one thread is release
                 // and it will start executing as soon as it re-acquires the lock
                 // on the mutex.
                 //
                 -- runningThreads;
                 conditionVariable.wait(mutex);
                 ++ runningThreads;
             }
             job = jobQue.getJobAndRemoveFromQue();
         }
         job.execute();
    }
    {
        // Extra code to count threads sp we can add more if required.
        RAIILocker doLock(mutex);
        -- actualThreads;
        -- runningThreads;
    }
}

Pool::AddJob(Job job)
{
    RAIILocker doLock(mutex);

    // This is where you would check to see if you need more threads.
    if (runningThreads == actualThreads) // Plus some other conditions.
    {
        // increment both counts. When it waits we decrease the running count.
        startThread(threadroutine);
    }
    jobQue.push_back(job);
    conditionVariable.notify_one();  // This releases one worker thread
                                     // from the call to wait() above.
                                     // Note: The worker thread will not start
                                     //       until this thread releases the mutex.
}
Pool::Pool()
{
runningThreads=0;
实际读数=0;
完成=错误;
jobQue.Init();
mutex.Init();
conditionVariable.Init();
对于(int-loop=0;loop
我认为您需要重新考虑您的设计。在一个简单的模型中,庄家线程将工作分配给玩家线程,庄家将工作放入消息队列中,并让其中一个玩家在有机会时拿起工作


在您的情况下,经销商正在积极管理线程池,因为它保留了关于哪些播放器线程空闲,哪些线程繁忙的知识。因为经销商知道哪个玩家空闲,所以经销商可以主动地将空闲的任务传递给该玩家,并使用一个简单的信号量(或cond var)向该玩家发送信号-每个玩家有一个信号量。在这种情况下,经销商可以通过给线程一个kill-myve任务来主动销毁空闲线程

现在我找到了一个解决方案,但并不是那么完美。 我有一个名为free的易失性成员变量,它在池中存储空闲线程的数量

void thread_pool::thread_function()
{
    free++;
    command_queue::handler_t handler;
    while (handler = tasks.pop(timeout))
    {
        free--;
        handler();
        free++;
    }
    free--;
}
当我将任务分配给线程时,我会执行如下操作

if (free == 0)
    threads.create_thread(boost::bind(&thread_pool::thread_function, this));

同步仍然存在问题,因为如果上下文在释放后被切换——在
thread\u函数中
我们可能会创建一个新的线程,实际上我们并不需要它,但是由于任务队列是线程安全的,所以这没有问题,这只是一个不必要的开销。你能提出解决方案吗?你对此有何看法?也许最好让它保持原样,然后在这里再进行一次同步?

另一个想法。您可以查询消息队列的长度。如果太长,请创建一个新的工作人员。

你知道,用小注释编写代码通常比用少量代码编写英语要清晰得多。在一个块中发布完整的代码。
boost::thread_group
可以简化后者,也就是说,您可以调用
interrupt_all()
在等待时请求关闭。其想法是创建一个智能线程池,它不会让不必要的线程保持活动状态。因此,这不会解决问题,只会通过更改任务来避免问题:)
if (free == 0)
    threads.create_thread(boost::bind(&thread_pool::thread_function, this));