L'Événement / La Tâche De La File D'Attente De Multithreading C++
Je voudrais créer une classe dont les méthodes peuvent être appelées à partir de plusieurs threads. mais au lieu de l'exécution de la méthode du fil à partir de laquelle il a été appelé, il doit procéder à tous dans son propre thread. Aucun résultat ne doit être renvoyé, et Il ne devrait pas bloquer le thread appelant.
Une première tentative de mise en Œuvre, j'ai inclus ci-dessous. Les méthodes publiques insérer un pointeur de fonction et les données dans une File d'attente de travail, qui le thread de travail prend alors la. Cependant, il n'est pas particulièrement joli code et ajouter de nouvelles méthodes, c'est encombrant.
Idéalement, je voudrais l'utiliser comme une classe de base qui je peux facilement ajouter des méthodes (avec un nombre variable d'arguments) avec un minimum de tracas et de la duplication de code.
Quelle est la meilleure façon de le faire? Est il un code qui fait la même chose? Grâce
#include <queue>
using namespace std;
class GThreadObject
{
class event
{
public:
void (GThreadObject::*funcPtr)(void *);
void * data;
};
public:
void functionOne(char * argOne, int argTwo);
private:
void workerThread();
queue<GThreadObject::event*> jobQueue;
void functionOneProxy(void * buffer);
void functionOneInternal(char * argOne, int argTwo);
};
#include <iostream>
#include "GThreadObject.h"
using namespace std;
/* On a continuous loop, reading tasks from queue
* When a new event is received it executes the attached function pointer
* It should block on a condition, but Thread code removed to decrease clutter
*/
void GThreadObject::workerThread()
{
//New Event added, process it
GThreadObject::event * receivedEvent = jobQueue.front();
//Execute the function pointer with the attached data
(*this.*receivedEvent->funcPtr)(receivedEvent->data);
}
/*
* This is the public interface, Can be called from child threads
* Instead of executing the event directly it adds it to a job queue
* Then the workerThread picks it up and executes all tasks on the same thread
*/
void GThreadObject::functionOne(char * argOne, int argTwo)
{
//Malloc an object the size of the function arguments
int argumentSize = sizeof(char*)+sizeof(int);
void * myData = malloc(argumentSize);
//Copy the data passed to this function into the buffer
memcpy(myData, &argOne, argumentSize);
//Create the event and push it on to the queue
GThreadObject::event * myEvent = new event;
myEvent->data = myData;
myEvent->funcPtr = >hreadObject::functionOneProxy;
jobQueue.push(myEvent);
//This would be send a thread condition signal, replaced with a simple call here
this->workerThread();
}
/*
* This handles the actual event
*/
void GThreadObject::functionOneInternal(char * argOne, int argTwo)
{
cout << "We've made it to functionTwo char*:" << argOne << " int:" << argTwo << endl;
//Now do the work
}
/*
* This is the function I would like to remove if possible
* Split the void * buffer into arguments for the internal Function
*/
void GThreadObject::functionOneProxy(void * buffer)
{
char * cBuff = (char*)buffer;
functionOneInternal((char*)*((unsigned int*)cBuff), (int)*(cBuff+sizeof(char*)));
};
int main()
{
GThreadObject myObj;
myObj.functionOne("My Message", 23);
return 0;
}
OriginalL'auteur Ben Reeves | 2009-05-29
Vous devez vous connecter pour publier un commentaire.
Il y a Les contrats à terme bibliothèque fait son chemin dans Boost et le C++ de la bibliothèque standard. Il y a aussi quelque chose du même genre dans ACE, mais je n'aimerais pas à le recommander à n'importe qui (comme @lothar déjà souligné, c'est l'Objet Actif.)
L'avenir de la bibliothèque feront partie de Boost 1.41. Il est également disponible en tant que partie de mon C++0x bibliothèque de threads mise en œuvre dans le stdthread.co.uk
Merci, Anthony. Agréable de vous entendre 🙂
OriginalL'auteur Nikolai Fetissov
La POCO bibliothèque a quelque chose le long des mêmes lignes, appelées ActiveMethod (avec quelques fonctionnalités liées par exemple ActiveResult) dans le filetage de la section. Le code source est disponible et facile à comprendre.
OriginalL'auteur Duck
Vous pouvez résoudre ce problème en utilisant Boost Fil de la bibliothèque. Quelque chose comme ceci (demi-pseudo):
Veuillez également noter comment RAII nous permettre de nous rendre ce code plus compact et mieux gérer.
OriginalL'auteur nhaa123
Vous pourriez être intéressé par Objet Actif l'un des ACE Modèles de la ACE cadre.
Comme Nikolai souligné les contrats à terme sont prévu pour la norme C++ certain moment dans le futur (pun intended).
OriginalL'auteur lothar
Pour l'extensibilité et la maintenabilité (et d'autres sur la responsabilité), vous pouvez définir une classe abstraite (ou d'interface) pour le "travail" que le thread est à effectuer. Utilisateur(s) de votre pool de threads mise en œuvre de cette interface et de faire référence à l'objet pour le pool de threads. Ceci est très similaire à Symbian Active de l'Objet de conception: chaque AO sous-classes CActive et ont à mettre en œuvre des méthodes telles que Run() et Cancel().
Pour des raisons de simplicité de votre interface (classe abstraite) pourrait être aussi simple que:
Alors le fil de la piscine, ou seul thread à accepter les demandes aurait quelque chose comme:
Naturellement, vous avez plusieurs tâches peuvent avoir toutes sortes d'extra-setters /getters /attributs et tout ce que vous devez dans tous les horizons de la vie. Cependant, la seule doit soit mettre en œuvre la méthode Run(), ce qui permettrait d'effectuer de longs calculs:
Des conseils sur la mise en œuvre de la serrure sans file d'attente?
Il existe assez peu de bons exemples de sans verrouillage des files d'attente sur le net (c'est l'un des plus faciles de verrouillage de structures libres pour mettre en œuvre). C'est le seul que j'ai coupé mes dents lors de la prise sur la serrure sans train en marche: boyet.com/Articles/LockfreeQueue.html
Oh, juste un peu attention que l'article que j'ai lié à sufferes de l'ABA problème, il y a un lien en haut de la page de détails de ce problème et il y a de meilleures solutions sur le net pour ça, mais c'est l'un des plus simple des tutoriels que j'ai vu à apprendre.
OriginalL'auteur Ignas Limanauskas
Voici une classe, j'ai écrit pour un même but (je l'utilise pour la gestion d'événements, mais vous pouvez bien sûr le renommer en ActionQueue -- et renommer ses méthodes).
Vous l'utiliser comme ceci:
Avec la fonction que vous voulez l'appeler:
void foo (const int x, const int y) { /*...*/}
Et:
EventQueue q;
q.AddEvent (boost::bind (foo, 10, 20));
Dans le thread de travail
q.PlayOutEvents ();
Remarque: Il devrait être assez facile d'ajouter du code à bloc, à condition d'éviter de consommer des cycles de PROCESSEUR.
Le code (Visual Studio 2003 avec boost 1.34.1):
J'espère que cette aide. 🙂
Martin Bilski
OriginalL'auteur
Ci-dessous est une mise en œuvre qui ne nécessitent pas un "functionProxy" la méthode. Même si il est plus facile d'ajouter de nouvelles méthodes, il est toujours en désordre.
Boost::Bind et "Futures" ne semblent comme ils le feraient bien rangé, beaucoup de cela. Je crois que je vais avoir un coup d'oeil à l'élan de code et de voir comment il fonctionne. Merci pour vos suggestions de tout le monde.
GThreadObject.h
GThreadObject.cpp
main.cpp
Edit: Juste pour être complet, je n'ai qu'une mise en œuvre avec Boost::bind. Principales Différences:
À l'aide de la poussée de la mise en œuvre de 10 000 000 d'Itérations de functionOne (), il a fallu ~19sec. Toutefois, la non améliorer la mise en œuvre a pris seulement ~6,5 sec. Si Environ 3x plus lent. Je devine trouver un bon non-fermeture de la file d'attente sera la plus grande performance de goulot de bouteille ici. Mais il est encore tout à fait une grande différence.
OriginalL'auteur Ben Reeves
Vous devriez jeter un oeil à la Boost ASIO de la bibliothèque. Il est conçu pour l'expédition des événements de manière asynchrone. Il peut être couplé avec la poussée de la bibliothèque de Threads pour construire le système que vous avez décrit.
Vous devez instancier un seul
boost::asio::io_service
l'objet et la planification d'une série d'événements asynchrones (boost::asio::io_service::post
ouboost::asio::io_service::dispatch
). Ensuite, vous appelez larun
fonction de membre de n threads. Leio_service
objet est thread-safe et garantit que votre asynchrone gestionnaires ne seront expédiées dans un fil à partir de laquelle vous avez appeléio_service::run
.La
boost::asio::strand
objet est également utile pour la simple synchronisation des threads.Pour ce qu'il vaut, je pense que le pilote ASIO de la bibliothèque est très une solution élégante à ce problème.
OriginalL'auteur Dan