Ce face std::thread.join()? (Programare, C++, Multithreading, Mutex)

Guagua a intrebat.
a intrebat.

De către definiție din referința C++:

Blochează firul curent până când firul identificat prin *this își termină execuția.

Asta înseamnă că atunci când se utilizează .join(), nu este necesar să se utilizeze mutex.lock() atunci când acel fir de execuție apelează o anumită funcție? Sunt nou în materie de excludere reciprocă și de threading, așa că sunt cam confuz.

Notă: Am găsit o carte C++ Concurrency in Action și o citesc. Este foarte bine scrisă pentru un începător în materie de multithreading ca mine.

Vă mulțumesc tuturor pentru ajutor.

Comentarii

  • Mulțumesc David pentru că ai editat pentru a fi mai clar. Martin: Am încercat să caut pe Google, dar am văzut 4-5 exemple care aveau aceeași idee și nu arată cu adevărat ce face join din punctul meu de vedere… Am crezut că cei de aici sunt cunoscători și ar oferi cele mai bune răspunsuri cu exemple de cod. –  > Por Guagua.
4 răspunsuri
Joel

Încă mai ai nevoie de mutexuri și condiții. Alăturarea unui fir de execuție face ca un fir de execuție să aștepte ca un alt fir să termine de executat. Aveți în continuare nevoie de mutexuri pentru a proteja resursele partajate. Aceasta permite ca main() din acest exemplu să aștepte ca toate firele de execuție să se termine înainte de a se închide.

#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>

using namespace std;



int global_counter = 0;
std::mutex counter_mutex;

void five_thread_fn(){
    for(int i = 0; i<5; i++){
        counter_mutex.lock();
        global_counter++;
        counter_mutex.unlock();
        std::cout << "Updated from five_thread"  << endl;
        std::this_thread::sleep_for(std::chrono::seconds(5));
    }
    //When this thread finishes we wait for it to join
}

void ten_thread_fn(){
    for(int i = 0; i<10; i++){
        counter_mutex.lock();
        global_counter++;
        counter_mutex.unlock();
        std::cout << "Updated from ten_thread"  << endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    //When this thread finishes we wait for it to join
}
int main(int argc, char *argv[]) {
    std::cout << "starting thread ten..." << std::endl;
    std::thread ten_thread(ten_thread_fn);

    std::cout << "Running ten thread" << endl;
    std::thread five_thread(five_thread_fn);


    ten_thread.join();
    std::cout << "Ten Thread is done." << std::endl;
    five_thread.join();
    std::cout << "Five Thread is done." << std::endl;
}

Rețineți că rezultatul ar putea arăta astfel:

starting thread ten...
Running ten thread
Updated frUopmd atteend_ tfhrroema df
ive_thread
Updated from ten_thread
Updated from ten_thread
Updated from ten_thread
Updated from ten_thread
Updated from five_thread
Updated from ten_thread
Updated from ten_thread
Updated from ten_thread
Updated from ten_thread
Updated from ten_thread
Updated from five_thread
Ten Thread is done.
Updated from five_thread
Updated from five_thread
Five Thread is done.

Deoarece std::cout este o resursă partajată, accesul și utilizarea acesteia ar trebui să fie, de asemenea, protejate prin mutex.

Comentarii

  • Mulțumesc Joel, deci aici ten_thread.join() ar spune programului ten_thread că a terminat și că poate trece la pasul următor? –  > Por Guagua.
  • firul de execuție care rulează main() se va bloca la apelul lui ten_thread.join() până când ten_thread se întoarce. Odată ce execuția ten_thread se termină, execuția main este autorizată să continue. Sper că acest lucru vă ajută. –  > Por Joel.
  • Updated fr[U]o[p]m[d] [at]te[e]n[d]_[ ]t[f]h[r]r[o]e[m]a[ ]d[five_thread] –  > Por Mubin Icyer.
eveniment

join() oprește firul curent până când se termină un altul. mutex oprește firul curent până când proprietarul mutexului îl eliberează sau îl blochează imediat dacă nu este blocat. Așadar, acești tipi sunt destul de diferiți

Comentarii

    16

  • Totuși, prefer „suspendare” în loc de „oprește”. –  > Por Sebastian.
helloworld134

Blochează firul curent până când se termină execuția firului pe care este apelat join().

Dacă nu se specifică join() sau dettach() pe firul respectiv, atunci va rezulta o eroare de execuție, deoarece firul principal/curent își va finaliza execuția, iar celălalt fir creat va fi încă în execuție.

Martin James

std::thread.join are trei funcții la care mă pot gândi la prima vedere și alte câteva:

a) Încurajează crearea/terminarea/distrugerea continuă a firelor de execuție, ceea ce afectează performanța și crește probabilitatea de scurgeri, fugă de fire de execuție, fugă de memorie și pierderea generală a controlului asupra aplicației dumneavoastră.

b) Încurcă gestionarii de evenimente GUI prin impunerea unor așteptări nedorite, ceea ce duce la „aplicații cu clepsidră” care nu răspund, pe care clienții dvs. le vor urî.

c) Face ca aplicațiile să nu reușească să se închidă, deoarece așteaptă terminarea unui fir de execuție nerezonabil și neîntrerupt.

d) Alte lucruri rele.

Înțeleg că sunteți nou în domeniul multithreading-ului și vă doresc tot ce este mai bun în acest sens. De asemenea, luați în considerare faptul că am băut mult Adnams Broadside în seara asta, dar:

Join(), și prietenii săi din alte limbaje, cum ar fi TThread.WaitFor, (Delphi), sunt pentru multithreadingul eficient ceea ce a fost Windows ME pentru sistemele de operare.

Vă rugăm să vă străduiți să progresați și să ajungeți să înțelegeți alte concepte multithread – pool-uri, sarcini, fire de execuție pe durata de viață a aplicației, comunicații între fire de execuție prin intermediul cozilor de așteptare producător-consumator. De fapt, aproape orice, cu excepția Join().