2017-01-25 4 views
3

Я пытаюсь создать область с областью.scope thread wrapper для std :: thread

#include <iostream> 
#include <thread> 

class ScopedThread { 
public: 
    template< class Function, class... Args> 
    explicit ScopedThread(int id, Function&& f, Args&&... args) 
     : m_thread(std::ref(f), std::forward<Args>(args)...) 
     , id(std::move(id)) { 
    } 



    int getId() const { return id; } 

    ~ScopedThread() { m_thread.join(); } 
private: 
    std::thread m_thread; 
    int id; 

}; 

class Worker { 
public: 
    Worker(int id): thd(id, &Worker::work, this) { } 

    void work() { 
     for(int i = 0; i < 10; i++) 
     std::cout << "I am working" << std::endl; 
    } 


private: 
    ScopedThread thd; 
}; 

int main() { 
    Worker(1); 
    Worker(2); 
    Worker(3); 
    Worker(4); 
} 

Когда я запускаю код, он сбрасывает ядро.

#0 0x00007ffcfbbc6380 in ??() 
#1 0x00000000004026c9 in std::_Mem_fn<void (Worker::*)()>::operator()<, void>(Worker*) const (this=0x7f0b43551de0, __object=0x7ffcfbbc63c0) 
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:601 
#2 0x00000000004025cd in std::__invoke<void (Worker::*)(), Worker*> ([email protected]: (void (Worker::*)(Worker * const)) 0x7ffcfbbc6380, this adjustment 4198629, 
    __args=<unknown type in /home/asit/cpp/scope_thd, CU 0x0, DIE 0x2abf>) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:247 
#3 0x0000000000402532 in std::reference_wrapper<void (Worker::*)()>::operator()<Worker*>(Worker*&&) const (this=0x1b27048, 
    __args=<unknown type in /home/asit/cpp/scope_thd, CU 0x0, DIE 0x57fb>) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:467 
#4 0x00000000004024d2 in std::_Bind_simple<std::reference_wrapper<void (Worker::*)()> (Worker*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) (this=0x1b27040) 
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1731 
#5 0x0000000000402485 in std::_Bind_simple<std::reference_wrapper<void (Worker::*)()> (Worker*)>::operator()() (this=0x1b27040) 
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1720 
#6 0x0000000000402119 in std::thread::_Impl<std::_Bind_simple<std::reference_wrapper<void (Worker::*)()> (Worker*)> >::_M_run() (this=0x1b27028) 
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:115 
#7 0x00007f0b44103a60 in ??() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#8 0x00007f0b43920184 in start_thread (arg=0x7f0b43552700) at pthread_create.c:312 
#9 0x00007f0b4364d37d in clone() at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111 

Может кто-нибудь сказать мне, как мне передать функции-члены и аргументы в базовый класс std :: thread? Я заметил, что ошибка сегментации происходит только в clang ++, а не в gcc.

Моя цель - сделать класс оболочки полностью заменяемым классом std :: thread. Класс Wrapper принимает новый аргумент для идентификатора потока.

+0

Вы строите с -pthread? –

+0

Да, я думаю, без -pthread, ошибка будет довольно многословной. Например, включить многопоточность для использования std :: thread: операция не разрешена –

+2

ну, вы уверены, что работаете точно так же, как вставить здесь? Потому что это работает для меня на gcc 4.8.4 –

ответ

6

Существует несколько проблем с вашей реализацией ScopedThread.

  1. Не нужно иметь дело с Function&& f отдельно. Просто обрабатывайте его как часть пакета args....

  2. Не нужно перемещать id.

    template< class... Args> 
    explicit ScopedThread(int id, Args&&... args) 
        : m_thread(std::forward<Args>(args)...) 
        , id(id) { 
    } 
    
  3. Вы должны убедиться, что ваш поток объединяемые перед вызовом .join().

    ~ScopedThread() { if(m_thread.joinable()) m_thread.join(); } 
    

Применение этих изменений prevents the segmentation fault on clang++.


Виной std::ref(f) - вы создаете временный reference_wrapper и передать его в конструктор std::thread «s, который использует std::invoke назвать.

Согласно g++ и UndefinedBehaviorSanitizer:

/usr/local/gcc-head/include/c++/7.0.1/bits/invoke.h:73:46:

runtime error: member call on misaligned address 0x7fff939ec8d3 for type 'struct Worker', which requires 8 byte alignment

Проблема заключается в том, что вы создаете ссылку на временную использованием std::ref(f), где временно находится &Worker::work.

Copying f instead of using std::ref doesn't cause any segfault or UndefinedBehaviorSanitizer diagnostic.

+0

, поэтому главное, чтобы использовать std :: forward (f) вместо std :: исх. Можете ли вы объяснить, почему это вызвало крах? –

+0

@MK. Просто добавлено объяснение. Я думаю, что проблема заключалась в том, что 'std :: ref (f)' создавал 'reference_wrapper' временный, а затем передавал его в' std :: thread :: thread' для вызова. –

+0

'if (m_thread.joinable()) m_thread.join();': когда поток может быть уже уничтожен в этом случае? не уничтожаются члены при выходе из деструктора? –

Смежные вопросы