c++ 11 sync(dynamische erzeugung, sync)



  • Hallo liebe Leute,

    Ich erzeuge Threads dynamisch(schleife)

    std::vector<std::thread*> threadVector;
    for (int i = 0; i < mNumberofPlayers; i++) {
    
    		std::thread *f = new std::thread(Start, i);
    		threadVector.push_back(f);
    	}
    
    	for (int i = 0; i < mNumberofPlayers; i++) {
    
    		threadVector[i]->join();
    	}
    

    Und möchte die nun auch dynamisch synchronisieren(2 wartet auf den 1, 3 auf den 2 etc).
    SInnhaftigkeit sei hier dann natürlich mal so hingestellt..

    edit: dynamisch erstelle future variablen die dann dynamisch nach der reihe abgefragt werden die mit std::launch::dereffed gestartet werden?(find ich net wirklich schön)

    Und nochwas:

    bei folgendem beispiel werden dynamisch 255 thread aufgemacht auf die ich bis zum cout warten will(zeile 10 und 11)
    funktioniert hier antprlich ganz gut, allerdings blockiert der Mutex im Workerthread nicht alle anderen Workethreads?(also es kann immer nur einer ausgeführt werden?!?)

    void WorkerThread_2(size_t i){
    	std::lock_guard<std::mutex> lck(threadMut2);
            //working...
    	dataReady2=true;
    		condVar2.notify_one();
    }
    
    for(int i=0; i< 255; i++){
    
    			std::thread *newThread= new std::thread(WorkerThread_2, i);
    			myThreadVector2.push_back(newThread);
    
    		}
    		//
    	//sync, wait for 255 workerthread_2
    		for(int i=0;i<255;i++){
    			std::unique_lock<std::mutex> lck(threadMut2);
    			condVar2.wait(lck, []{return dataReady2;});
    		}
    


  • wrock schrieb:

    Ich erzeuge Threads dynamisch(schleife)

    std::vector<std::thread*> threadVector;
    

    Nein! 😡
    Nimm std::vectorstd::thread ohne Sinnloszeiger. Für irgendetwas gibts Move-Semantik.

    Ansonsten, was willst du genau erreichen? Deine Frage ist unklar...


  • Mod

    std::vector<std::thread*> threadVector;
    for (int i = 0; i < mNumberofPlayers; i++) {
    
            std::thread *f = new std::thread(Start, i);
            threadVector.push_back(f);
        }
    

    ➡

    std::vector<std::thread> threadVector;
    for (int i = 0; i < mNumberofPlayers; i++)
            threadVector.emplace_back(Start, i);
    


  • raiiler schrieb:

    wrock schrieb:

    Ich erzeuge Threads dynamisch(schleife)

    std::vector<std::thread*> threadVector;
    

    Nein! 😡
    Nimm std::vectorstd::thread ohne Sinnloszeiger. Für irgendetwas gibts Move-Semantik.

    Ansonsten, was willst du genau erreichen? Deine Frage ist unklar...

    ähm...Zeile 4 das Ganze wird zur Laufzeit erzeugt inwiefern sollte das so unschön sein?

    in der schleife werden i Threads erzeugt, Thread 2 soll auf Thread 1 warten bevor er weitermacht, thread 3 auf thread 2...etc. jetzt nicht so schwer...

    edit: hab emplace_back nachgelesen...
    ...soll heißen ich brauch mich ums löschen dann auch nicht mehr kümmern oder? nice 😃

    schreibt doch dazu, c++11 haben noch nicht alle alles intus...

    edit:edit:

    Arcoth schrieb:

    std::vectorstd::thread threadVector;
    for (int i = 0; i < mNumberofPlayers; i++)
    threadVector.emplace_back(std::thread(Start, i));



  • Du solltest std::thread btw nie™ raw benutzen btw, sondern immer eine Klasse drum bauen die im Destruktor entweder joined oder detached.



  • wrock schrieb:

    Arcoth schrieb:

    std::vectorstd::thread threadVector;
    for (int i = 0; i < mNumberofPlayers; i++)
    threadVector.emplace_back(std::thread(Start, i));

    Nein, das war schon richtig von Arcoth, das std::thread davor ist unnötig.



  • cooky451 schrieb:

    Du solltest std::thread btw nie™ raw benutzen btw, sondern immer eine Klasse drum bauen die im Destruktor entweder joined oder detached.

    Auf keinen Fall! Das führt beides zu Problemen:

    {
      int local_variable; // gedacht um Resultat von t zu halten
      cookies_detaching_thread t([&local_variable]{...});
      throw exception();
      t.join();             // wird nie
      return local_variable; // ausgeführt
    } // t1.detach() // -> t1 schreibt den Stack kaputt
    
    {
      int local_variable; // gedacht um Resultat von t zu halten
      cookies_joining_thread t([&local_variable]{...});
      throw exception();
      t.join();              // wird nie
      return local_variable; // ausgeführt
    } // t.join() // -> Es wird auf t gewartet, aber es macht keinen Sinn t weiter auszuführen
    


  • Am besten benutzt du auch keine Schleifen, das kann zu Problemen führen:

    for (std::uint16_t i = 0; i < 123456; ++i)
      ; // Kommt nie aus der Schleife raus
    

    Ah ne moment vielleicht liegt das Problem hier nicht bei der Schleife. Am besten du benutzt einfach keine ints, die sind gefährlich.



  • Ich glaube wir sollten auf beiden Seiten von voreiligen Generalisierungen abweichen.

    Irgendwo hat cooky Recht, aber antiraii (doofer Name oO) hat natürlich auch schöne Beispiele angegeben, die crashen. Daher, es kommt auf den Anwendungsfall an.



  • dazu gleich mal ne Frage, beim joinale/detached thread wie muss cih da den construktor aufbauen damit er alle argumente weiterleitet? also das nichts velroren geht?

    class joining_thread{
    
    public:
    	joining_thread(){}
    
    	~joining_thread(){
    		mThread.join();
    	}
    private:
    	std::thread mThread;
    
    };
    


  • So in der Art:

    template <typename Function, typename... Args>
    	explicit scoped_thread(Function&& f, Args&&... args)
    		: thr_(std::forward<Function>(f), std::forward<Args>(args)...)
    	{}
    


  • cooky451 schrieb:

    So in der Art:

    template <typename Function, typename... Args>
    	explicit scoped_thread(Function&& f, Args&&... args)
    		: thr_(std::forward<Function>(f), std::forward<Args>(args)...)
    	{}
    

    Dank dir !

    noch eine Frage

    joining_thread t1(&Mikado::Start,this,0);
    	joining_thread t2(&Mikado::Start,this,1);
    	joining_thread t3(&Mikado::Start,this,2);
    
    std::vector<joining_thread> myVec1;
    	myVec1.emplace_back(&Mikado::Start,this,0);
    	myVec1.emplace_back(&Mikado::Start,this,1);
    	myVec1.emplace_back(&Mikado::Start,this,2);
    

    Die beiden Varianten müssten sich doch gleich verhalten oder?
    Angelegt werden sie beide gleich, und bei empalce werden sie nur in den Vektor verschoben.
    Nichtsdestotrotz funktioniertrt die Erste Variante mit meinm Program einwandfrei, und die Zweite nicht....

    kann mir eig nur einen Fehler mit der this reference vorstellen...


  • Mod

    Die beiden Varianten müssten sich doch gleich verhalten oder?

    Kommt auf joining_thread an, weil die Elemente des vector s intern wahrscheinlich noch gemoved werden.



  • naja eigentlich nichts aufregende mehr

    die copy konstruktoren sind leer implementiert

    und die move semantik so:

    //move semantik
    	joining_thread(joining_thread&& other ):mThread(std::move(other.mThread)){}
    	joining_thread& operator=(joining_thread&& other){
    		mThread=std::move(other.mThread);
    		return *this;
    	}
    

    demanch sollte es ja richtig verschoben werden oder?

    Das Program kompiliert richtig weiter, sieht allerdings so aus als habe ehr bei den Mutex/Threads aufwecken dann ein problem...


  • Mod

    Präzise Fehlerbeschreibungen sind das A und O beim Fragen stellen.



  • func1(){//incr counter
    if ((mPlayerCounter + 1) == mNumberofPlayers) {
    		mPlayerCounter = 0;
    	} else {
    		mPlayerCounter++;
    	}
    //wake up all threads
    std::unique_lock<std::mutex> lck(mCritMutex);
    	mCondVar.notify_all();
    }
    
    func2(int PlayerID){
    while(true){
      if(mPlayerCounter==PlayerID){
         //do things
         func1();
       }
    
         //going to sleep, wakes up when change in PlayerCounter
    		//lambda functions is used for
         std::unique_lock<std::mutex> lck(mCritMutex);
         mCondVar.wait(lck,[&]{return mPlayerCounter==PlayerID;});
    }
    }
    
    std::vector<joining_thread> myVec1;
    
    	/*joining_thread t1(&MyClass::func2,this,0);
    	joining_thread t2(&MyClass::func2,this,1);
    	joining_thread t3(&MyClass::func2,this,2);
    */
    
    	myVec1.emplace_back(&MyClass::func2,this,0);
    	myVec1.emplace_back(&MyClass::func2,this,1);
    	myVec1.emplace_back(&MyClass::func2,this,2);
    

    erste Variante(ausgeklammert) funktioniert>:
    thread 0 wird ausgeführt
    thread 1 wird ausgeführt
    thread 2 wird ausgeführt
    thread 0 wird ausgeführt
    .
    .
    .

    variante 2:
    thread 0 wird ausgeführt
    thread 1 wird ausgeführt
    -->ende

    joining_thread

    class joining_thread{
    
    public:
    
    	template <typename Function, typename... Args>
    	    explicit joining_thread(Function&& f, Args&&... args)
    	        : mThread(std::forward<Function>(f), std::forward<Args>(args)...)
    	    {}
    
    	~joining_thread(){
    		mThread.join();
    	}
    
    	//copy semantik
    	joining_thread(joining_thread& other ){}
    	joining_thread& operator=(const joining_thread& other ){return *this;}
    
    	//move semantik
    	joining_thread(joining_thread&& other ):mThread(std::move(other.mThread)){}
    	joining_thread& operator=(joining_thread&& other){
    		mThread=std::move(other.mThread);
    		return *this;
    	}
    
    private:
    	std::thread mThread;
    };
    

Anmelden zum Antworten