Code Monkey home page Code Monkey logo

Comments (5)

kermado avatar kermado commented on May 27, 2024

I don't think that this is sufficient. The wait predicate AFAIK is to guard against spurious wakeup. It's probably recommended, but I don't think that it solves the race condition.

Your call operator should look more like this:

void operator()()
{
  std::unique_lock<std::mutex> lock(m_pool->m_conditional_mutex);
  while (!m_pool->m_shutdown) {
  {
    if (m_pool->m_queue.empty()) {
      m_pool->m_conditional_lock.wait(lock, [this] { return this->m_pool->m_shutdown || this->m_pool->m_queue.empty() == false; });
    }
    std::function<void()> func;
    if (m_pool->m_queue.dequeue(func)) {
      func();
    }
  }
}

The problem described is then fixed by locking the mutex in your shutdown() function. Note that wait() releases the lock when called and acquires the lock when woken. You need to acquire the lock in order to prevent wait() being called after the call to notify_all() in shutdown().

void shutdown()
{
  {
    std::lock_guard<std::mutex> lock(m_conditional_mutex);
    m_shutdown = true;
    m_conditional_lock.notify_all();
  }
  
  for (int i = 0; i < m_threads.size(); ++i)
  {
    if (m_threads[i].joinable())
    {
      m_threads[i].join();
    }
  }
}

Similarly, in submit(), you need to acquire the lock before calling notify_all() to prevent notify_all() being called between checking whether the queue is empty and calling wait().

{
  std::lock_guard<std::mutex> lock(m_conditional_mutex);
  m_conditional_lock.notify_one();
}

from thread-pool.

yvoinov avatar yvoinov commented on May 27, 2024

https://stackoverflow.com/questions/35775501/c-should-condition-variable-be-notified-under-lock

from thread-pool.

yvoinov avatar yvoinov commented on May 27, 2024

https://stackoverflow.com/questions/17101922/do-i-have-to-acquire-lock-before-calling-condition-variable-notify-one/17102100

from thread-pool.

kermado avatar kermado commented on May 27, 2024

@yvoinov In the case of submit(), if we don't lock the mutex then I believe that notify_one() could be called between checking whether the queue is empty and wait(). In that case, we will wait forever, or until something else notifies the condition variable. I placed the lock to ensure that we only notify if the other thread is currently waiting. If you don't lock then how else do you prevent this race condition?

https://stackoverflow.com/questions/20982270/sync-is-unreliable-using-stdatomic-and-stdcondition-variable

from thread-pool.

yvoinov avatar yvoinov commented on May 27, 2024

@yvoinov In the case of submit(), if we don't lock the mutex then I believe that notify_one() could be called between checking whether the queue is empty and wait(). In that case, we will wait forever, or until something else notifies the condition variable. I placed the lock to ensure that we only notify if the other thread is currently waiting. If you don't lock then how else do you prevent this race condition?

https://stackoverflow.com/questions/20982270/sync-is-unreliable-using-stdatomic-and-stdcondition-variable

After a lot of testing, I'm using quite different thread pool implementation:

https://github.com/yvoinov/thread-pool-cpp

There is no race condition on submit. Without lock notify_*. This implementation works perfectly, no deadlocks, no races.

To prevent lost wakeup it is enough to lock conditional variable mutex during notify_one(). It described here:

http://www.modernescpp.com/index.php/c-core-guidelines-be-aware-of-the-traps-of-condition-variables

from thread-pool.

Related Issues (15)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.