multithreading - C++ class with thread - destructor, constructor, move constructor? -


i going through book concurrency in action c++. there example there of class called scoped_thread (pg 27), ensures raii idiom , thread has joined before respective end of scope.

this current example not allow used functions best requires move operator ,such emplace_back member function vector (?). way can call class constructor , possibly allow better optimization push_back. such, wanted add move constructor in class scoped_thread.

before present material, 2 questions follows

  1. what's reason non-parallel constructor , move constructor calls? how reduce them?
  2. is move constructor correct?
  3. i calling joinable() 2 times. in constructor. since created move constructor, i've had check joinable() in destructor well. may tie in question 2 if move constructor not good

see edit @ bottom of page before continuing

without further ado, here class code (link provided below full code in online compiler)

class scoped_thread

#define print(x) std::cout << x << std::endl;  static unsigned dtor_count = 0; static unsigned ctor_count = 0; static unsigned mtor_count = 0;  class scoped_thread {     thread t; public:     explicit scoped_thread(thread t_) :         t(std::move(t_))     {         if (!t.joinable())             throw std::logic_error("no thread!");         print("called scoped_thread ctor");         ctor_count++;     }     ~scoped_thread()     {         if (t.joinable())             t.join();         print("called scope_thread dtor");         dtor_count++;     }     scoped_thread(const scoped_thread&) = delete; // copy ctor     scoped_thread& operator=(const scoped_thread&) = delete; // copy init     scoped_thread(scoped_thread&& s) {         t = std::move(s.t);         mtor_count++;     }; }; 

the static variables used counter number of calls constructor, destructor , move constructor.

here example use. (note: commented section have been achieved without class)

example use

void do_work(int i) { print("made thread : " << i); }; void thread_vector_example() {     // normal version: have call thread join     /*     std::vector<std::thread> threads;     (unsigned = 0; < 10; ++i)         threads.push_back(std::thread(do_work, i));     std::for_each(begin(threads), end(threads),         std::mem_fn(&std::thread::join));        */      std::vector<scoped_thread> sthreads;     (unsigned = 0; < 10; ++i) {         sthreads.emplace_back(std::thread(do_work, i));     }    }    
  1. from g++ compiler (link given below) options g++ -std=c++14 -o2 -wall -pthread results follows

    • constructors called: 10
    • destructors called: 25
    • move constructors called: 15
  2. from visual studio c++ compiler (standard options)

    • constructors called: 10
    • destructors called: 35
    • move constructors called: 25

link file--> http://coliru.stacked-crooked.com/a/33ce9f3daab4dfda

edit

after calling reserve function i.e. sthreads.reserve(10), can have more better version calls constructor , destructor 10 times only. however, there still issue when remove move constructor class, code not compile

  1. what's reason non-parallel constructor , move constructor calls? how reduce them?

the reason 10 constructor calls construct 10 objects...

as you've figured out, reason move constructor calls reallocation of vector's internal storage due exceeding capacity , can rid of them reserving enough capacity before hand.

  1. is move constructor correct?

yes. once stop debugging constructor counts, scoped_thread(scoped_thread&& s) = default; should suffice.

i calling joinable() 2 times. in constructor. since created move constructor, i've had check joinable() in destructor well. may tie in question 2 if move constructor not good

the possibility of being moved require test in destructor. since it's tested in destructor, there isn't point in testing in constructor in opinion.

however, there still issue when remove move constructor class, code not compile

even though use vector in way causes no moves (reserve space , emplace new objects), objects must nevertheless movable. compiler cannot check never exceed capacity during run time , accordingly not generate code reallocation depends on type being movable or copyable.

here's bonus idea since want avoid moves. don't move thread constructor construct in-place instead (you may still want provide construct moves thread):

template<class fun, class... args>  explicit scoped_thread(fun&& f, args&&... args): t(std::forward<fun>(f), std::forward<args>(args)...) {}  //... sthreads.emplace_back(do_work, i); 

Comments

Popular posts from this blog

c++ - No viable overloaded operator for references a map -

java - Custom OutputStreamAppender not run: LOGBACK: No context given for <MYAPPENDER> -

java - Cannot secure connection using TLS -