2016-04-11 2 views
1

J'ai actuellement du code C++ synchrone qui effectue certaines tâches chronophages d'une manière séquentielle. J'envisage d'utiliser des coroutines Boost pour refactoriser cela en tâches parallèles. Le cœur des tâches est un appel à une bibliothèque externe qui fournit une API synchrone (qu'elle utilise actuellement) ou une API asynchrone qui doit être interrogée périodiquement pour faire progresser l'action et déterminer si elle a été complétée . L'API n'est pas adaptée aux threads, mais si la version asynchrone est utilisée, elle peut gérer plusieurs demandes simultanées tant que l'API d'interrogation elle-même n'est pas appelée simultanément. Comme je ne veux pas de changement de fil, il semble que je devrais utiliser l'API coroutine directement au lieu d'utiliser les wrappers ASIO ou similaire, mais je suis prêt à être persuadé autrement. 1.55 pour le moment, donc la librairie Fiber n'est pas disponible, mais cela semble aussi exagéré pour cet usage.)Impose le sommeil entre les exécutions coraperines

Ma question principale avec les coroutines pour le moment est que je ne suis pas sûr de savoir comment implémenter la limitation sur le scrutation - Dites que j'ai 100 tâches à exécuter en parallèle; Je veux qu'il fasse un tour d'interrogation à travers toutes les 100 tâches, puis dormez le fil pendant un certain temps. Certaines des tâches peuvent se terminer plus tôt que d'autres, donc plus tard, il pourrait toujours être interroger 40 tâches par boucle et ensuite dormir le même laps de temps. Je ne veux pas que l'on interroge la même tâche deux fois de suite sans un sommeil intermédiaire.

+1

Alors qu'est-ce qui vous empêche de coder ce que vous avez décrit? Codez la coroutine pour qu'elle ne cède que si elle veut dormir, puis parcourez simplement toutes les coroutines actives, dormez et répétez. –

+0

Probablement juste la méconnaissance. Peut-être que c'est plus simple que ce que je pensais. – Miral

Répondre

0

Ok, s'est avéré être beaucoup plus facile que je pensais. Voilà ce que j'ai fini avec jusqu'à présent:

typedef boost::coroutines::coroutine<void>::push_type coroutine; 
typedef boost::coroutines::coroutine<void>::pull_type yield_context; 
typedef std::vector<coroutine> coroutine_list; 

bool run_once_all(coroutine_list& coros) 
{ 
    bool pending = false; 
    for (auto& coro : coros) 
    { 
     if (coro) 
     { 
      coro(); 
      pending = pending || !coro.empty(); 
     } 
    } 
    return pending; 
} 

void run_all(coroutine_list& coros, 
      const boost::chrono::nanoseconds& idle_ns) 
{ 
    while (run_once_all(coros)) 
    { 
     boost::this_thread::sleep_for(idle_ns); 
    } 
} 

void run_all(coroutine_list& coros, yield_context& yield) 
{ 
    while (run_once_all(coros)) 
    { 
     yield(); 
    } 
} 

L'idée est que vous faites une coroutine_list, puis emplace_back fonctions lambda avec signature void (yield_context&), puis run_all. Le premier est pour le niveau supérieur et le second pour les coroutines imbriquées.

Semble fonctionner, bien que je ne l'ai pas encore donné une grande séance d'entraînement. En fait un peu surpris quelque chose comme ça n'est pas déjà dans la bibliothèque.