2

I am using a simple thread pool as below-

template<typename T>
class thread_safe_queue // thread safe worker queue.
{
private:
    std::atomic<bool> finish;
    mutable std::mutex mut;
    std::queue<T> data_queue;
    std::condition_variable data_cond;
public:
    thread_safe_queue() : finish{ false }
    {}

    ~thread_safe_queue()
    {}

    void setDone()
    {
        finish.store(true);
        data_cond.notify_one();
    }
    void push(T new_value)
    {
        std::lock_guard<std::mutex> lk(mut);
        data_queue.push(std::move(new_value));
        data_cond.notify_one();
    }

    void wait_and_pop(T& value)
    {
        std::unique_lock<std::mutex> lk(mut);
        data_cond.wait(lk, [this]
        {
            return false == data_queue.empty();
        });
        if (finish.load() == true)
            return;
        value = std::move(data_queue.front());
        data_queue.pop();
    }
    bool empty() const
    {
        std::lock_guard<std::mutex> lk(mut);
        return data_queue.empty();
    }
};

//Thread Pool
class ThreadPool
{
private:
    std::atomic<bool> done;
    unsigned thread_count;
    std::vector<std::thread> threads;

public:
    explicit ThreadPool(unsigned count = 1);

    ThreadPool(const ThreadPool & other) = delete;
    ThreadPool& operator = (const ThreadPool & other) = delete;

    ~ThreadPool()
    {
        done.store(true);
        work_queue.setDone();
        // IF thread is NOT marked detached and this is uncommented the worker threads waits infinitely.
        //for (auto &th : threads)
        //{
         //     if (th.joinable())
         //     th.join();
        // }
    }

    void init()
    {
        try
        {
            thread_count = std::min(thread_count, std::thread::hardware_concurrency());
            for (unsigned i = 0; i < thread_count; ++i)
            {
                threads.emplace_back(std::move(std::thread(&ThreadPool::workerThread, this)));
                threads.back().detach();
              // here the problem is if i dont mark it detatched thread infinitely waits for condition.
             // if i comment out the detach line and uncomment out comment lines in ~ThreadPool main threads waits infinitely.
            }
        }
        catch (...)
        {
            done.store(true);
            throw;
        }
    }

    void workerThread()
    {
        while (true)
        {
            std::function<void()> task;
            work_queue.wait_and_pop(task);
            if (done == true)
                break;
            task();
        }
    }
    void submit(std::function<void(void)> fn)
    {
        work_queue.push(fn);
    }
};

The usage is like :

struct start
{
public:
    ThreadPool::ThreadPool m_NotifPool;
    ThreadPool::ThreadPool m_SnapPool;
    start()
    {
        m_NotifPool.init();
        m_SnapPool.init();
    }
};    
int main()
{
    start s;
    return 0;
}    

I am running this code on visual studio 2013. The problem is when main thread exits. The program crashes. It throws exception. Please help me with what am i doing wrong? How do i stop the worker thread properly? I have spent quite some time but still figuring out what is the issue.

Thanks for your help in advance.

user888270
  • 613
  • 2
  • 8
  • 16
  • 1
    I'm not sure, but it seems the queue would locked (the first `wait_and_pop` hold the mutex while waiting for the queue to be empty, the next `workerThread` never get the mutex). If that's the case, the thread would never exited gracefully. – Leben Asa Jun 24 '16 at 05:58
  • Try replacing `return false == data_queue.empty();` with `return !data_queue.empty() || finish;` – screwnut Jun 25 '16 at 17:00

3 Answers3

1

I am not familiar with threads in c++ but have worked with threading in C. In C what actually happens is when you creates child threads of from the main thread then you have to stop the main thread until the childs finishes. If main exits the threads becomes zombie. I think C don't throw an exception in case of Zombies. And may be you are getting exception because of these zombies only. Try stopping the main until the childs finishes and see if it works.

  • but in C also you can mark a thread detached and it shall exit once the main thread finishes and main need not wait for child threads to finish. I think thats what detaching the thread means. – user888270 Jun 24 '16 at 05:47
1

When main exits, detached threads are allowed to continue running, however, object s is destroyed. So, as your threads attempt to access members of object s, you are running into UB.

See accepted answer of this question for more details about your issue : What happens to a detached thread when main() exits?

Community
  • 1
  • 1
shrike
  • 4,449
  • 2
  • 22
  • 38
0

A rule of thumb would be not to detach threads from main, but signal thread pool that app is ending and join all thread. Or do as is answered in What happens to a detached thread when main() exits?

Community
  • 1
  • 1
Mateusz
  • 131
  • 3