C++ std :: vector的独立std :: threads

Men*_*des 10 c++ multithreading vector c++11 stdthread

我正在构建一个实时软件,我有一个主要的无限循环main()和用于读取和处理数据的线程.

其中一个问题是保持一个std::vector正在运行的线程向它们发送信号并监视执行.所以我把这段代码放在一起:

#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <chrono>

namespace readerThread {

    void start(int id)
    {
        while (1)
        {
            std::cout << "Reader " << id << " running..." <<  std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        }
    }

}


int main() 
{

        int readers[] = { 1, 2, 3 };

        std::vector<std::thread> readerThreads;

        for (int &reader : readers)
        {
            std::thread th(readerThread::start, reader);
            readerThreads.push_back(th);
        }

        while(true)
        {
            std::cout << "Waiting..." << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(10000));
        }

        return 0;
}
Run Code Online (Sandbox Code Playgroud)

它甚至没有编译,得到这个错误:

In file included from /usr/local/include/c++/5.1.0/x86_64-unknown-linux-gnu/bits/c++allocator.h:33:0,
                 from /usr/local/include/c++/5.1.0/bits/allocator.h:46,
                 from /usr/local/include/c++/5.1.0/string:41,
                 from /usr/local/include/c++/5.1.0/bits/locale_classes.h:40,
                 from /usr/local/include/c++/5.1.0/bits/ios_base.h:41,
                 from /usr/local/include/c++/5.1.0/ios:42,
                 from /usr/local/include/c++/5.1.0/ostream:38,
                 from /usr/local/include/c++/5.1.0/iostream:39,
                 from main.cpp:1:
/usr/local/include/c++/5.1.0/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::thread; _Args = {const std::thread&}; _Tp = std::thread]':
/usr/local/include/c++/5.1.0/bits/alloc_traits.h:256:4:   required from 'static std::_Require<std::allocator_traits<_Alloc>::__has_construct<_Tp, _Args ...> > std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {const std::thread&}; _Alloc = std::allocator<std::thread>; std::_Require<std::allocator_traits<_Alloc>::__has_construct<_Tp, _Args ...> > = void]'
/usr/local/include/c++/5.1.0/bits/alloc_traits.h:402:16:   required from 'static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {const std::thread&}; _Alloc = std::allocator<std::thread>; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]'
/usr/local/include/c++/5.1.0/bits/stl_vector.h:917:30:   required from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::thread; _Alloc = std::allocator<std::thread>; std::vector<_Tp, _Alloc>::value_type = std::thread]'
main.cpp:37:30:   required from here
/usr/local/include/c++/5.1.0/ext/new_allocator.h:120:4: error: use of deleted function 'std::thread::thread(const std::thread&)'
  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
    ^
In file included from main.cpp:4:0:
/usr/local/include/c++/5.1.0/thread:126:5: note: declared here
     thread(const thread&) = delete;
     ^
Run Code Online (Sandbox Code Playgroud)

线程是独立的,所以我不需要调用join主程序也不需要调用任何线程......

所以,这是我的疑惑:

为什么我的代码不能编译?

这是存储线程向量的正确方法吗?

谢谢你的帮助......

PS:原始代码在这里:

Ami*_*ory 15

你需要使用类似的东西

readerThreads.push_back(move(th));
Run Code Online (Sandbox Code Playgroud)

这将产生th一个rvalue,并导致移动ctor被调用.的拷贝构造函数thread禁用设计(见安东尼·威廉斯的C++并发在行动).

  • 是! 现在我记得那些来自其他读物..感谢帮助......像魅力一样工作...... (2认同)

kfs*_*one 6

/usr/local/include/c++/5.1.0/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::thread; _Args = {const std::thread&}; _Tp = std::thread]':
/usr/local/include/c++/5.1.0/bits/alloc_traits.h:256:4:   required from 'static std::_Require<std::allocator_traits<_Alloc>::__has_construct<_Tp, _Args ...> > std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {const std::thread&}; _Alloc = std::allocator<std::thread>; std::_Require<std::allocator_traits<_Alloc>::__has_construct<_Tp, _Args ...> > = void]'
/usr/local/include/c++/5.1.0/bits/alloc_traits.h:402:16:   required from 'static decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::thread; _Args = {const std::thread&}; _Alloc = std::allocator<std::thread>; decltype (_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = <type error>]'
/usr/local/include/c++/5.1.0/bits/stl_vector.h:917:30:   required from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::thread; _Alloc = std::allocator<std::thread>; std::vector<_Tp, _Alloc>::value_type = std::thread]'
main.cpp:37:30:   required from here
/usr/local/include/c++/5.1.0/ext/new_allocator.h:120:4: error: use of deleted function 'std::thread::thread(const std::thread&)'
  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
Run Code Online (Sandbox Code Playgroud)

让我们把它剥掉一点.

error: use of deleted function 'std::thread::thread(const std::thread&)'
Run Code Online (Sandbox Code Playgroud)

你的代码正在做一些试图引入的代码std::thread.

required from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&)
Run Code Online (Sandbox Code Playgroud)

push_back 是罪魁祸首.

std::thread是不可复制的 - 复制线程意味着什么?

std::thread t1([](){});
std::thread t2 = t1;
Run Code Online (Sandbox Code Playgroud)

因此,std::thread对象的实例旨在成为唯一所有者.除了简单的混乱之外,还会产生很多痛苦.

然而,它们是可移动的.

std::thread t1([](){});
std::thread t2 = std::move(t1);
Run Code Online (Sandbox Code Playgroud)

t1不再是有效的线程描述符,它描述的线程现在归其所有t2.

要将这些东西放入容器中,您可以使用std::movestd::emplace/ std::emplace_back.

std::vector<std::thread> threads;
threads.push_back(std::move(std::thread([](){})));
threads.emplace_back([](){});
Run Code Online (Sandbox Code Playgroud)

虽然您的代码专注于此特定问题,但我要指出,C++标准将其声明为在线程仍然连接且未连接时调用线程析构函数的错误.

int main() {
    std::thread t1([](){ while (true) { std::this_thread::yield(); } };
}
Run Code Online (Sandbox Code Playgroud)

当主终止时,调用t1 .~thread(),它检测到线程仍然连接但未连接,这会引发异常,导致关闭崩溃.

你需要join()线程,等待它终止运行,或者detach()它.如果你想使用join(),你需要一些方法告诉线程停止,如果你detach()的程序可能在线程中间退出做类似写入数据等,你可能会引入一个严重的错误.

#include <thread>
#include <chrono>
#include <future>

int main () {
  std::promise<void> cnx_promise;
  std::shared_future<void> cnx_future;

  std::thread t1([cnx_future]() {
      while (cnx_future.valid()) {
        std::this_thread::yield();
      }
  });

  std::this_thread::sleep_for(std::chrono::seconds(1));

  cnx_promise.set_value();

  t1.join();
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们使用一个承诺让线程知道什么时候停止运行,但你可以使用条件变量,信号等,甚至只是一个std::atomic<bool> ok_to_run { true };你测试为false 的简单.


Set*_*eth 6

另一个有效的变体是在 vector.push_back 调用中创建您的线程对象。在这种情况下不需要调用 std::move 因为它已经是一个右值(因此它将被移动)。

for (int &reader : readers)
    readerThreads.push_back(std::thread(readerThread::start, reader));
Run Code Online (Sandbox Code Playgroud)