std::map::end() 是否从不同线程返回不同的结果?

发布于 2025-01-10 15:39:41 字数 2071 浏览 0 评论 0原文

我有这个 线程池保存一个对象容器,每当它收到一个新对象时数据块,它用相同的新数据块更新所有对象。工作是在线程池的构造中预先分配的,并且该工作存储在以下数据成员中

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

因此,如果此 map 中的线程元素在其 中具有元素 1,2 和 3 Vector,这意味着每次新数据点到达时,它负责更新索引为 1,2 和 3 的对象。

如果我有十个对象和三个线程,工作时间表可能看起来像这样

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

在每个 工作人员thread,它会进行一些计算,然后将其计算添加到共享聚合变量中。不过我很困惑,因为一旦所有线程都完成后,只有最后一个线程应该对计算进行最后的处理。出于某种原因,这个块偶尔 执行两次:

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);
}

输出如下所示:

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

这段代码如何运行两次? 我只从 m_work_schedule 中读取,但这种情况的偶然性表明它是某种竞争条件。不过,我正在努力思考对此的任何可能的解释。

  • std::map::end() 是否在不同线程中返回不同的内容?
  • 一个线程使用 std::map::end() 进行读取会影响另一个线程的读取吗?**
  • 如果最后一个线程在所有线程完成工作之前完成,它是否可以再次随机进入该代码块?
  • 线程ID可以改变吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

掩饰不了的爱 2025-01-17 15:39:41

我敢打赌您的问题是

        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));
        }

在您仍在填充 m_work_schedule_map 的同时启动线程。据我所知,没有锁。所以你有同时的读者和作者

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文