2016-07-27 12 views
0

일부 직원이 여기까지 나를 도왔습니다. Call function inside a lambda passed to a thread 내 작업자 클래스가 이동 생성자와 이동 operator=을 지원할 수 있지만 클래스에 문제가 있습니다. 스레드에 대한 복사 (또는 참조)를 통해 클래스 값에 액세스 할 수 있도록 this을 바인딩합니다. 다음은 여러 개의 atomic<bool>, condition_variablemutex입니다.스레드를 멤버 변수로 사용하는 클래스의 작업 이동

그러나 스레드가 다른 조건 변수 mutexatomic에 바인딩 된 이후로 이동하려고하면 아무 작업도 수행되지 않습니다. 이 문제를 어떻게 해결할 수 있습니까? 좀 더 복잡한 객체를 사용해야하고 람다 대신에 그것을 움직여야하므로 스레드가 그것에 대한 레퍼 런스를 가질 수 있습니까? 또는 다른 대안이 있습니다. 항상 도움이 될 것입니다 :).

다음은 구현의 스 니펫 (MWE)입니다.

class worker { 
public: 
    template <class Fn, class... Args> 
    explicit worker(Fn func, Args... args) { 
     t = std::thread(
      [&func, this](Args... cargs) -> void { 
       std::unique_lock<std::mutex> lock(mtx); 
       while (true) { 
        cond.wait(lock, [&]() -> bool { return ready; }); 

        if (terminate) 
         break; 

        func(cargs...); 

        ready = false; 
       } 
      }, 
      std::move(args)...); 
    } 

    worker(worker &&w) : t(std::move(w.t)) { /* here there is trouble */ } 

    worker &operator=(worker &&w) { 
     t = std::move(w.t); 
     terminate.store(wt.terminate); 
     ready.store(wt.ready); 
     return *this; 
     /* here too */ 
    } 

    ~worker() { 
     terminate = true; 
     if (t.joinable()) { 
      run_once(); 
      t.join(); 
     } 
    } 

    worker() {} 

    void run_once() { 
     std::unique_lock<std::mutex> lock(mtx); 
     ready = true; 
     cond.notify_one(); 
    } 

bool done() { return !ready; } 

private: 
    std::thread t; 
    std::atomic<bool> ready, terminate; // What can I do with all these? 
    std::mutex mtx;      // 
    std::condition_variable cond;  // 
}; 

int main() { 
    worker t; 
    t = worker([]() -> void { cout << "Woof" << endl; }); 
    t.run_once(); 
    while(!t.done()) ; 
    return 0; 
} 

큰 코드 덤프는 죄송합니다.

+0

문제는 한 스레드에서 사용중인 개체를 다른 스레드에서 아래로 이동한다는 것입니다. 질문 : 왜? 개체를 동적으로 만들고 스마트 포인터를 사용하십시오. – kfsone

+0

@kfsone Y-yeah는 내가 두 번째 질문에 대해 궁금해하는 점이었고, 좀 더 우아한 것이 있는지 또는 내가 빠져 있는지 알고 싶었습니다. – Aram

답변

2

worker은 복사 할 수없고 움직일 수 없다고 말하고 worker의 사용자에게 남겨두고 이동하려는 경우 unique_ptr으로 저장합니다. 전혀 문제가 없습니다. 실제로는 평범한 것입니다.

이 클래스를 이동 가능하게 만들려면 Worker::Impl 중첩 클래스를 worker이 소유하고 unique_ptr으로 만드십시오. Impl 클래스는 복사 불가능하고 움직일 수 없으며 기본적으로 현재 worker 클래스입니다. 람다는 worker 클래스가 아니라 Impl 클래스에 대한 포인터를 갖습니다. worker 클래스는 Implunique_ptr을 제외한 아무것도 포함하지 않으며 Impl 클래스의 함수로 전달하는 함수와 기본 복사 및 이동 연산자/연산자는 두 클래스 모두에서 올바르게 작동합니다 (작업자는 복사 가능하지만 이동 가능하지 않습니다. 복사 불가능하고 움직일 수 없음).

+0

좋아, 아마 두 번째 작업을 수행 할 것입니다. 감사. – Aram

+0

@Aram 강력하게 추천합니다. 기술적으로 가능하다는 것을 보여주기 위해 완벽하게 표현했습니다. 이 문제를 '고치는'현대적인 방법은 아무 것도하지 않는 것입니다. 카피 불가능/비 이동 클래스를 가지고 클래스의 사용자가 그것을 처리하게하십시오. – David

+0

내가 물을 수 있다면 그 접근법의 단점은 무엇입니까? – Aram