2

I created a thread pooling to distribute 100 computations between 4 threads.

I cannot understand why the following code stucks after 4 computations. After each computation, the thread must be released and I expect that .joinable() returns false so the program will continue.

Results:

[[[01] calculated 
] calculated 
2] calculated 
[3] calculated 

Code:

#include <string>
#include <iostream>
#include <vector>
#include <thread>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>
#include <cmath>

class AClass
{
public:

    void calculation_single(std::vector<double> *s,int index)
    {
        (*s)[index]=sin(double(index));
        std::cout<<"["<<index<<"] calculated \n";
    }

    void calculation()
    {
        const uint N_nums=100;
        const uint N_threads=4;
        std::vector<double> A;
        A.assign(N_nums,0.0);
        std::vector<std::thread> thread_pool;
        for(uint i=0;i<N_threads;i++)
            thread_pool.push_back(std::thread());

        uint A_index=0;
        while(A_index<N_nums)
        {
            int free_thread=-1;
            for(uint i=0;i<N_threads && free_thread<0;i++)
                if(!thread_pool[i].joinable())
                    free_thread=i;
            if(free_thread>-1)
            {
                thread_pool[free_thread]=
                    std::thread(
                        &AClass::calculation_single,
                        this,
                        &A,
                        int(A_index));
                A_index++;
            }
            else
            {
                boost::this_thread::sleep(boost::posix_time::milliseconds(1));
            }

        }

        // wait for tasks to finish
        for(std::thread& th : thread_pool)
            th.join();
    }

};

int main()
{
    AClass obj;
    obj.calculation();
    return 0;
}
ar2015
  • 5,558
  • 8
  • 53
  • 110

1 Answers1

2

A thread is joinable if it isn't empty basically.

A thread with a completed task is not empty.

std::thread bob;

bob is not joinable.

Your threads are. Nothing you do makes them not joinable.

Also, busy waiting is a crappy thread pool.

Create a consumer producer queue, with a pool of threads consuming tasks and an abort method. Feed tasks into the queue with via a packaged task and return a std::future<T>. Don't spawn a new thread per task.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • How should I fix this code? What to replace `joinable` with? – ar2015 Jan 02 '17 at 03:27
  • @ar2015 - You need to have each thread indicate that it completed its task by setting a per-thread mutex-protected flag, and signaling a condition variable. When the main loop sees that all threads are joinable, it acquires the mutex, and waits on the condition variable until at least one of the completion flags are set, and then subsequently joins the corresponding thread. This will also get rid of the silly busy-wait polling. – Sam Varshavchik Jan 02 '17 at 03:30
  • why *busy waiting* is a bad idea? – ar2015 Jan 02 '17 at 03:32
  • Because busy waiting wastes CPU cycles. You want to wait on a cond variable and be notified when it is signaled. – MK. Jan 02 '17 at 03:36
  • I dont know how to create a per-thread mutex-protected variable. Can anybody provides the suggested code please? – ar2015 Jan 02 '17 at 03:37
  • The same chapter in your C++ book where you learned how to use `std::thread` from will also explain to you how to use a `std::mutex` and a `std::condition_variable`. – Sam Varshavchik Jan 02 '17 at 04:03
  • @sam I'd launch an `async` returning a `future` for joining, and only at shutdown. You just queue stuff and the threads consume tasks off it. The "pool" manages the queue, a global abort flag, and a vector of futures. It does not assign tasks to individual threads or query their status. Creating or joining threads is overhead thread pools are supposed to avoid. – Yakk - Adam Nevraumont Jan 02 '17 at 04:06
  • http://stackoverflow.com/a/30180853/1774667 is a previous sketch. I think I have posted others. – Yakk - Adam Nevraumont Jan 02 '17 at 04:28