Home > Net >  does std::map::end() return different results from different threads?
does std::map::end() return different results from different threads?

Time:02-27

I've got this thread pool that holds a container of objects, and whenever it receives a new piece of data, it updates all the objects with the same new piece of data. The work is preallocated on the construction of the thread pool, and this work is stored in the following data member

std::map<std::thread::id, std::vector<unsigned>> m_work_schedule

So if a thread's element in this map has the elements 1,2 and 3 in its vector<unsigned>, that means it is responsible for updating the objects with indexes 1,2 and 3 every time a new data point arrives.

If I have ten objects and three threads, the work schedule might look something like this

140314357151488... 2, 5, 8, 
140314365544192... 1, 4, 7, 
140314373936896... 0, 3, 6, 9, 

In every worker thread, it does some calculation and then adds its calculation to the shared aggregate variable. I'm confused though, because once all the threads are finished, only the final thread is supposed to put the finishing touches on the calculation. For some reason, this block is occasionally executing twice:

if( std::prev(m_work_schedule.end())->first  == std::this_thread::get_id() ){
    std::cout << "about to finalize from thread " << std::this_thread::get_id() << ", which supposedly is equal to " <<  (--m_work_schedule.end())->first << "\n";
    m_working_agg = m_final_f(m_working_agg);
    m_out.set_value(m_working_agg);
}

The output looks like this:

139680503645952... 2, 5, 8, 
139680512038656... 1, 4, 7, 
139680520431360... 0, 3, 6, 9, 
about to finalize from thread 139680520431360, which supposedly is equal to 139680520431360
................
about to finalize from thread 139680503645952, which supposedly is equal to 139680503645952
terminate called after throwing an instance of 'std::future_error'
  what():  std::future_error: Promise already satisfied

How can this block of code run twice, though? I am only reading from m_work_schedule, but the occasional nature of this suggests it's some sort of race condition. I'm struggling to think of any possible explanation for this, though.

  • Does a std::map::end() return different things in different threads?
  • Does one thread's reading with std::map::end() affect another thread's?**
  • If the last thread finalizes before all threads are finished working, can it randomly enter this block of code again?
  • Can thread ids change?

CodePudding user response:

I bet your problem is here

        for(unsigned i=0; i< m_num_threads;   i) {
            m_threads.push_back( std::thread(&split_data_thread_pool::worker_thread, this));
            most_recent_id = m_threads.back().get_id();
            m_work_schedule.insert(std::pair<std::thread::id, std::vector<unsigned> >(most_recent_id, std::vector<unsigned>{}));
            m_has_new_dyn_input.insert(std::pair<std::thread::id, bool>(most_recent_id, false));
        }

you are starting the threads while you are still populating the m_work_schedule_map. And as far as I can see there is no lock. So you have simultaneous readers and writers

  • Related