Maison >Java >javaDidacticiel >interprétation boost :: io_service

interprétation boost :: io_service

坏嘻嘻
坏嘻嘻original
2018-09-14 09:32:172019parcourir

io_servie implémente une file d'attente de tâches, où la tâche est la fonction void(void). Les deux interfaces les plus couramment utilisées de Io_servie sont post et run. Post délivre les tâches dans la file d'attente des tâches. Run exécute les tâches dans la file d'attente jusqu'à ce que toutes soient exécutées, et run peut être appelé par N threads. Io_service est une file d'attente entièrement sécurisée pour les threads.

interprétation boost::io_service

asio est une bibliothèque de modèles de programmation asynchrone C++ fournie par boost. Sa classe principale io_service fournit des fonctions de file d'attente et de distribution de tâches dans la programmation multi-thread, principalement dans socket. utilisé comme pilote d'événement dans la programmation io (port de complétion, sélection, sondage, epoll, etc.).

Modèle de file d'attente

Chaque io_service possède une file d'attente de tâches publique et plusieurs files d'attente de tâches privées. La file d'attente publique est partagée par chaque thread et la file d'attente privée est exclusive à chaque thread.

interprétation boost :: io_service

Le processus d'exécution des tâches de io_service est à peu près le suivant :

  1. Appelez la méthode run et entrez dans la boucle principale

  2. Déterminez si la file d'attente publique est vide. Si elle n'est pas vide, supprimez la tâche et exécutez-la. Lorsque le nombre de tâches est supérieur à 1, réveillez les autres threads inactifs en même temps. time;

  3. L'exécution de la tâche est terminée et les tâches dans la file d'attente privée de chaque thread sont déplacées vers la file d'attente des tâches publique

  4. déclenche le réacteur. Sous Linux, c'est généralement epoll. Lorsqu'il y a un événement, la tâche de l'événement correspondant est placée dans la file d'attente privée.

  5. Lorsque la file d'attente est vide, ajoutez le thread actuel à la file d'attente des threads inactifs et entrez dans l'état d'attente, en attendant que les autres threads se réveillent (task_operation).

  6. Lorsque l'utilisateur appelle post, la tâche est directement livrée dans la file d'attente publique op_queue.

Modèle de pool de threads

Il existe deux modèles de pool de threads couramment utilisés :

Le premier est que plusieurs threads partagent une file d'attente de tâches et que l'utilisateur place la tâche Postée dans la file d'attente des tâches, d'autres threads se font concurrence pour obtenir l'exécution de la tâche à partir de la file d'attente. Combiné avec boost::thread, le pool de threads peut être implémenté en appelant la méthode run dans plusieurs threads :

using namespace boost;
using namespace boost::asio;
io_service ios;
int thread_num = 10;
thread *t[thread_num] = {0};
// 创建线程池
for(int i = 0; i < thread_num; ++i)
{
    t[i] = new thread(bind(&io_service::run, &ios));
}

// 向任务队列中投递任务,该任务将随机由一个调用run方法的线程执行
ios.post(func);

// 等待线程退出
for(int i = 0; i < thread_num; ++i)
{
    t[i]->join();
}
Il est facile de voir que le goulot d'étranglement de ce pool de threads réside dans une file d'attente de tâches et plusieurs threads La concurrence pour les tâches peut facilement conduire à une dégradation des performances dans les grands programmes simultanés.

L'autre est que chaque thread maintient une file d'attente de tâches. Les utilisateurs peuvent choisir de livrer des tâches à l'une des files d'attente de tâches de manière aléatoire ou en rotation. Les tâches de la file d'attente de tâches ne peuvent être consommées que par le thread dans lequel elles se trouvent. est situé. Ce type de pool de threads a également une implémentation correspondante (io_service_pool) dans l'exemple boost. La méthode de base consiste à créer plusieurs objets io_service, chacun correspondant à un thread. Le code est le suivant :

<.>

Ce qui suit est un diagramme de classes basé sur l'environnement Linux, car certaines classes ont des définitions différentes sous Windows.
using namespace boost;
using namespace boost::asio;
int thread_num = 10;
io_service ios[thread_num];
thread *t[thread_num] = {0};
// 创建线程池
for(int i = 0; i < thread_num; ++i)
{
    t[i] = new thread(bind(&io_service::run, &ios[i]));
}

// 轮训投递任务
for(int i = 0; i < thread_num; ++i)
{
    ios[i].post(func);
}   

// 等待线程退出
for(int i = 0; i < thread_num; ++i)
{
    t[i]->join();
}

interprétation boost :: io_serviceio_service définit l'interface principale, et l'implémentation sous Linux est task_io_service.

task_io_service définit principalement trois choses :

    Un réacteur, qui est un pilote d'événement tel qu'un port d'achèvement, une sélection, un sondage et un epoll ;
  1. Une file d'attente de tâches publique op_queue, utilisée pour stocker les tâches publiées par les utilisateurs et les tâches renvoyées par le réacteur

  2. Variables liées au thread ; io_service lui-même ne créera aucun thread, mais il enregistrera certaines informations sur les appels de thread, telles que les files d'attente privées de thread, etc.

  3. De plus, task_io_service maintient également une liste de threads inactifs et réveille l'un des threads inactifs lorsque des tâches supplémentaires arrivent. Dans le pool de threads de file d'attente à tâche unique Linux commun, une variable de condition est utilisée pour réveiller le thread. Dans un système multicœur, un appel pthread_cond_signal réveillera un ou plusieurs threads en état d'attente (voir https://linux). .die.net/man/3/pthread_cond_signal), bien qu'il n'y ait qu'une seule tâche, si la méthode des threads inactifs est utilisée, un seul thread inactif est réveillé lorsqu'il y a une tâche, ce qui peut réduire de nombreux réveils inutiles.

  4. La classe thread_info_base maintient un pool de mémoire simple avec un seul morceau de mémoire. Elle peut réduire la surcharge d'allocation de mémoire uniquement lorsque la mémoire est continuellement demandée et libérée.

Le rôle de io_service::work : io_service::run reviendra immédiatement lorsque la tâche est terminée. Ce n'est pas ce que vous souhaitez lors de l'écriture d'un programme de service résident. La solution proposée par boost est de définir un travail. variable , c'est incroyable à première vue. Cette variable qui semble n'avoir rien à voir avec io_server peut en fait contrôler le comportement de run. Lorsque vous ouvrez le code source, vous pouvez voir que la mise en œuvre du travail est étonnamment simple. work_started() de io_service dans le constructeur, de sorte que le nombre de tâches en attente (++outstanding_work_) soit supérieur à 0. Dans ce cas, io_service::run considère qu'il y a toujours des tâches à traiter et ne renvoie pas.

Recommandations associées :

Angular met à jour la directive_AngularJS en fonction de l'état du service

Introduction aux méthodes d'utilisation de l'usine et du service dans AngularJS_AngularJS

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn