2011-10-17 2 views
1

Quelle est la meilleure façon d'effectuer ce qui suit en C++. Alors que ma méthode actuelle fonctionne, je ne suis pas sûr que c'est la meilleure façon d'aller:passant "this" à un thread C++

1) J'ai une classe de maître qui a une fonction dans ce

2) J'ai un fil qui prend quelques instructions sur un prise puis exécute l'une des fonctions dans la classe maître

3) Il y a un certain nombre de threads accéder aux différentes fonctions dans la classe maître

je crée la classe maître, puis créer des instances des classes de fil de le maître. Le constructeur de la classe thread reçoit le pointeur "this" pour le maître. Je peux ensuite exécuter des fonctions de la classe master à l'intérieur des threads - c'est-à-dire que je reçois une commande pour faire quelque chose qui exécute une fonction dans la classe master à partir du thread. J'ai mutex etc pour éviter les problèmes de course. Est-ce que je vais dans le mauvais sens? Il semble que les classes de threads devraient hériter de la classe master ou une autre approche serait de ne pas avoir de classes de thread séparées mais de les avoir comme fonctions de la classe master mais cela devient laid .

+1

Pouvez-vous un peu de code? Connaissez-vous la distinction entre classes et instances? Y a-t-il une instance de classe de maître pour chaque thread? –

+0

Non, il existe une seule classe principale à partir de laquelle les threads sont générés. Les threads ont juste besoin d'accéder aux fonctions des membres maîtres et à certaines variables. –

Répondre

1

Ça me semble bon. Dans mes serveurs, il s'appelle 'SCB' - ServerControlBlock - et donne accès à des services comme les pools IOCPbuffer/socket, l'enregistreur, l'accès à l'interface utilisateur pour les messages d'état/erreur et tout ce qui doit être commun à tous les threads du gestionnaire. Fonctionne bien et je ne le vois pas comme un hack.

Je crée le SCB, (et m'assure dans le ctor que tous les services accessibles à travers lui sont démarrés et prêts à l'emploi), avant de créer le pool de threads qui utilise le SCB - pas de singletonny méchant.

Mfg, Martin

+0

Ok sonne bien - je vais continuer à utiliser "this" dans mon pool de threads. –

1

Les classes de thread séparées sont assez normales, surtout si elles ont des fonctionnalités spécifiques. Je n'hériterais pas du fil principal.

+0

Oui, je suppose que la question principale que j'ai est de passer le pointeur "this" au mauvais codage des classes de threads ou est-ce assez standard. Cela ressemble à un peu un hack –

+0

Ce n'est pas un hack si vous traitez la classe de maître comme un singleton etc. –

+0

Passer le "ceci" pointeur est normal, c'est une chose commune à faire. Comme l'a dit Aditya, vous pouvez aussi faire de votre classe principale un singleton pour que vous ne passiez aucun pointeur, vous appelez simplement MainClass :: getInst() -> quand vous voulez des méthodes d'accès. –

1

En passant le pointeur this à fils est pas, en soi, mauvais. Ce que vous faites avec ça peut l'être.

Le pointeur this est comme n'importe quel autre type de données POD-ish. C'est juste un morceau de bits. Les choses qui sont dans this pourraient être plus que PODs cependant, et passer ce qui est en fait un pointeur à ses membres peut être dangereux pour toutes les raisons habituelles. Chaque fois que vous partagez quelque chose à travers les threads, cela introduit des conditions de course potentielles et des blocages. Le moyen élémentaire pour résoudre ces conflits est, bien sûr, d'introduire la synchronisation sous la forme de mutex, de sémaphores, etc., mais cela peut avoir l'effet surprenant de sérialiser votre application. Dites que vous avez un thread lire des données à partir d'un socket et le stocker dans un tampon de commande synchronisé, et un autre thread qui lit à partir de ce tampon de commande. Les deux threads utilisent le même mutex, qui protège le tampon. Tout va bien, non?

Eh bien, peut-être pas. Vos threads peuvent être sérialisés si vous ne faites pas très attention à la manière dont vous verrouillez le tampon. Vous avez probablement créé des threads distincts pour les codes buffer-insert et buffer-remove afin qu'ils puissent fonctionner en parallèle. Mais si vous verrouillez le tampon avec chaque insertion & chaque suppression, alors une seule de ces opérations peut être exécutée à la fois. Tant que vous écrivez dans le tampon, vous ne pouvez pas en lire et vice versa.

Vous pouvez essayer d'affiner les verrous afin qu'ils soient aussi courts que possible, mais tant que vous avez partagé des données synchronisées, vous aurez un certain degré de sérialisation.

Une autre approche consiste à transférer explicitement les données à un autre thread et à supprimer autant de partage de données que possible. Au lieu d'écrire et de lire à partir d'un tampon comme ci-dessus, par exemple, votre code de socket peut créer une sorte d'objet Command sur le tas (par exemple Command* cmd = new Command(...);) et le transmettre à l'autre thread. (Une façon de le faire dans Windows est via le mécanisme QueueUserAPC).

Il y a des avantages & des inconvénients aux deux approches.La méthode de synchronisation a l'avantage d'être plus simple à comprendre et à mettre en œuvre à la surface, mais l'inconvénient potentiel d'être beaucoup plus difficile à déboguer si vous gâchez quelque chose. La méthode de transfert peut rendre impossible la plupart des problèmes inhérents à la synchronisation (rendant ainsi plus simple), mais il faut du temps pour allouer de la mémoire sur le tas.