2009-04-01 8 views
-1

Je travaille avec une bibliothèque de classes C++ qui fournit une classe de base Thread dans laquelle l'utilisateur doit mettre en œuvre une méthode run().Comment passer des paramètres à un objet Thread?

Existe-t-il un moyen recommandé de transmettre les paramètres à cette méthode run()? En ce moment Je préfère les passer via le constructeur (comme pointeurs).

Répondre

2

Je ne suis pas sûr de C++, mais c'est comme ça que vous le feriez en Java. Vous auriez une classe qui étend Thread (ou implémente Runnable) et un constructeur avec les paramètres que vous souhaitez passer. Ensuite, lorsque vous créez le nouveau thread, vous devez passer dans les arguments, puis démarrez le fil, quelque chose comme ceci:

Thread t = new MyThread(args...); 
t.start(); 

doit être le même dans votre cas.

+3

Ha, la réponse Java a été acceptée à une question taggés C++ :) Ce –

+0

est certainement pas la réponse à cette question –

0

Il est acceptable de les transmettre via le constructeur. Assurez-vous simplement que les pointeurs vivent plus longtemps que le fil.

0

Un problème courant avec le démarrage du thread est que les arguments transmis n'existent que sur la pile de la fonction appelante. Le démarrage des threads est souvent différé, de sorte que la fonction d'appel revient et que le thread ne démarre réellement que peu de temps après, moment auquel les arguments n'existent plus.

Une solution consiste à créer un événement, puis à démarrer le thread, en passant l'événement comme l'un des arguments. La fonction de démarrage attend alors l'événement, qui est signalé par le thread quand il a terminé le démarrage.

+0

Quelle est la raison pour laquelle on doit utiliser un pool de threads. –

+0

Je ne l'ai jamais essayé. Ce qui me frappe, c'est que vous devez changer le nombre de threads dans la piscine, car la charge de travail varie, et cela semble une complication gênante. –

0

Vous pouvez transmettre les paramètres en tant que membres de la classe de threads. Le thread qui crée le thread peut vraisemblablement appeler d'autres méthodes et/ou appeler des fonctions membres avant que le thread ne démarre. Par conséquent, il peut peupler tous les membres nécessaires pour que cela fonctionne. Ensuite, lorsque la méthode d'exécution est appelée, elle aura les informations nécessaires pour démarrer.

Je suppose que vous utiliserez un objet séparé pour chaque thread.

Vous mettriez normalement tous les fils que vous créez dans un tableau, vecteur, etc.

+0

L'approche avec l'utilisation des méthodes getter est sympa, mais je pense que je préfère passer des paramètres via le constructeur Thread. J'aime avoir un objet utilisable après l'appel du constructeur. –

0

Eh bien, je préfère mettre les paramètres dans la méthode Start(), vous pouvez donc avoir un constructeur protégé, et n'a pas besoin de cascader les paramètres via le constructeur de la classe dérivée.

Je prolly laisse mon decleration ressembler à quelque chose comme ceci:

class Thread 
{ 
public: 
    virtual void Start(int parameterCount, void *pars); 
protected: 
    Thread(); 
    virtual void run(int parameterCount, void *pars) = 0; 
} 

Assurez-vous que vos paramètres sont en quelque sorte sous contrat, par exemple # 1 sera int, # 2 sera un double etc. etc :)

1

Une alternative est d'étendre cette classe Thread pour accepter un foncteur comme seul paramètre constructeur, de sorte que vous puissiez lier n'importe quel appel à l'intérieur.

Ensuite, la classe utilisant les threads n'a pas besoin d'hériter de Thread, mais seulement un (ou plusieurs) membre Thread. Le foncteur appelle un point de départ que vous voulez (une méthode de la classe avec tous les paramètres)

1

Voici un modèle typique:

1) Définir une structure de données qui encapsule toutes les données de votre fil a besoin 2) le thread principal, instancier une copie de la structure de données sur le tas en utilisant l'opérateur new. 3) Remplissez la structure de données, placez le pointeur sur void *, passez le void * à la procédure thread par tous les moyens qui vous sont fournis par votre bibliothèque de threads. 4) Lorsque le thread de travail obtient le void *, il le réinterprète_cast vers la structure de données, puis prend possession de l'objet. Ce qui signifie que lorsque le thread est fait avec les données, le thread le libère, par opposition au thread principal qui le désalloue.

Voici un exemple de code que vous pouvez compiler & test sous Windows.

#include "stdafx.h" 
    #include <windows.h> 
    #include <process.h> 

    struct ThreadData 
    { 
     HANDLE isRunning_; 
    }; 

    DWORD WINAPI threadProc(void* v) 
    { 

    ThreadData* data = reinterpret_cast<ThreadData*>(v); 
    if(!data) 
     return 0; 

    // tell the main thread that we are up & running 
    SetEvent(data->isRunning_); 

    // do your work here... 

    return 1; 
} 

int main() 
{ 
    // must use heap-based allocation here so that we can transfer ownership 
    // of this ThreadData object to the worker thread. In other words, 
    // the threadProc() function will own & deallocate this resource when it's 
    // done with it. 
    ThreadData * data = new ThreadData; 
    data->isRunning_ = CreateEvent(0, 1, 0, 0); 

    // kick off the new thread, passing the thread data 
    DWORD id = 0; 
    HANDLE thread = CreateThread(0, 0, threadProc, reinterpret_cast<void*>(data), 0, &id); 

    // wait for the worker thread to get up & running 
    // 
    // in real code, you need to check the return value from WFSO and handle it acordingly. 
    // Here I assume the retval is WAIT_OBJECT_0, indicating that the data->isRunning_ event 
    // has become signaled 
    WaitForSingleObject(data->isRunning_,INFINITE); 

    // we're done, wait for the thread to die 
    WaitForSingleObject(thread, INFINITE); 
    CloseHandle(thread); 

    return 0; 

}