1
votes

Pourquoi un programme C ++ multithreading se bloque si nous n'utilisons pas join (), alors qu'un programme Java similaire ne le fait pas

Disons que nous avons le programme C ++ suivant

public class HelloWorld {
    public static void main(String[] args) {
        Thread t = new Thread(new Hello());
        t.start();

    }

}

class Hello implements Runnable {

    public void run() {

          System.out.println("Hello") ;

}
}

Si nous n'appelons pas join dans ce code, notre programme plantera car le thread principal se terminera avant que le thread t1 ne soit terminé. Mais si nous avons le même programme en Java, le programme s'exécute normalement même si le main n'attend pas le thread.

void hello (){
   std :: cout << "HELLO"<<std::endl ;
}

int main(){

    std:: thread t(hello) ;
    t.join() ;

}

Alors pourquoi en Java le programme ne plante pas? comment le thread est exécuté même si le principal se termine en premier?


2 commentaires

java n'est pas c ++, pourquoi vous attendiez-vous à ce qu'ils soient les mêmes?


Pour être clair, le crash est dû au fait qu'un thread non joint provoquera std :: terminate pour être appelé dans le std :: thread destructor .


3 Réponses :


4
votes

C'est assez simple: contrairement au C ++, qui se termine une fois que main est terminé, un programme java ne se termine que si tous les threads (non-démon) (y compris main) sont terminés (cf., pour exemple, cette documentation de thread oracle):

Lorsqu'une machine virtuelle Java démarre, il y a généralement un seul thread non démon (qui appelle généralement la méthode nommée main de certains classe désignée). La machine virtuelle Java continue de s'exécuter threads jusqu'à ce que l'un des événements suivants se produise:

a. La méthode de sortie de la classe Runtime a été appelée et la sécurité manager a autorisé l'opération de sortie.

b. Tous les threads qui ne sont pas des threads démons sont morts, soit par retour de l'appel à la méthode run ou en lançant une exception qui se propage au-delà de la méthode run.

C ++, en revanche, commencera à détruire les objets avec une durée de stockage statique, et si un thread détaché est toujours en cours d'exécution et accède à ces objets, cela donne un comportement indéfini (cf., par exemple, ce projet de norme C ++ concernant l'arrêt du programme):

3.6.3 Résiliation

Destructeurs ([class.dtor]) pour les objets initialisés (c'est-à-dire les objets dont la durée de vie ([basic.life]) a commencé) avec une durée de stockage statique sont appelés à la suite du retour de main et à la suite de appelant std :: exit ([support.start.term]).


0 commentaires


4
votes

La réponse directe est la suivante: votre application plante car std :: thread appelle std :: terminate dans son destructeur si le thread n'a pas été joint et n'est pas détaché. C'est considéré comme un vilain bogue, d'oublier silencieusement les threads non détachés.

Vous pouvez éviter un crash immédiat si vous détachez le thread avant de revenir de main. Cependant, vous risquez toujours d'avoir toutes sortes de feux d'artifice possibles en raison de l'accès à std :: cout - qui est un objet global, et qui sera détruit après le retour de main , potentiellement pendant que votre fil y accède encore.


1 commentaires

Remarque: les programmeurs C ++ s'attendent à ce que les destructeurs d'objets ferment les fichiers, libèrent de la mémoire et nettoient généralement les choses. Dans certains univers fantastiques, nous aimerions que le destructeur std :: thread tue simplement le thread sans faire d'histoires. Mais comme en réalité, il n'y a pas de moyen raisonnable de "simplement tuer" un fil, il fait la meilleure chose suivante, qui est de vérifier que l'appelant l'a déjà tué ou a accepté la responsabilité de le tuer à l'avenir (en appelant t.detach () .) Les programmeurs Java n'ont pas le luxe des destructeurs. Ils doivent nettoyer les choses plus explicitement.