web-dev-qa-db-fra.com

Annuler un thread en utilisant pthread_cancel: bonne pratique ou mauvaise

J'ai un programme C++ sous Linux (CentOS 5.3) générant plusieurs threads qui sont dans une boucle infinie pour effectuer un travail et dormir pendant certaines minutes. Je dois maintenant annuler les threads en cours d'exécution au cas où une nouvelle notification de configuration arriverait in et fraîchement commencer une nouvelle série de threads, pour lesquels j'ai utilisé pthread_cancel. Ce que j'ai observé est que les threads ne sont pas arrêtés même après avoir reçu l'indication annulation, même des threads en sommeil remontaient une fois le sommeil terminé. .

Comme le comportement n'était pas souhaité, l'utilisation de pthread_cancel dans le scénario mentionné soulève la question de savoir s'il est une bonne ou une mauvaise pratique. 

Veuillez commenter l'utilisation de pthread_cancel dans le scénario mentionné ci-dessus.

23
Mandar

En général, l'annulation de thread n'est pas une très bonne idée. Il est préférable, dans la mesure du possible, d’avoir un indicateur partagé, utilisé par les threads pour sortir de la boucle. De cette façon, vous laisserez les threads effectuer tous les nettoyages nécessaires avant de quitter.

Sur la question des threads n'annulant pas réellement, la spécification POSIX détermine un ensemble de points d'annulation ( man 7 pthreads ). Les discussions ne peuvent être annulées qu'à ces points. Si votre boucle infinie ne contient pas de point d'annulation, vous pouvez en ajouter un en appelant pthread_testcancel. Si pthread_cancel a été appelé, il sera traité à ce stade.

Si vous écrivez du code C++ protégé contre les exceptions (voir http://www.boost.org/community/exception_safety.html ), votre code est naturellement prêt à être annulé. glibs lève une exception C++ sur le thread cancel , afin que vos destructeurs puissent effectuer le nettoyage approprié.

10
Maxim Egorushkin

Vous pouvez faire l'équivalent du code ci-dessous.

#include <pthread.h>
#include <cxxabi.h>
#include <unistd.h>
...
void *Control(void* pparam)
{
    try
    {
        // do your work here, maybe long loop
    }   
    catch (abi::__forced_unwind&)
    {  // handle pthread_cancel stack unwinding exception
        throw;
    }
    catch (exception &ex) 
    {
        throw ex;
    }
}

int main()
{
    pthread_t tid;
    int rtn;
    rtn = pthread_create( &tid, NULL, Control, NULL );

    usleep(500);
    // some other work here

    rtn = pthtead_cancel( tid );
}
0
Jack

J'utiliserais boost :: asio.

Quelque chose comme:

struct Wait {
  Wait() : timer_(io_service_), run_(true) {}

  boost::asio::io_service io_service_;
  mutable boost::asio::deadline_timer timer_;
  bool run_;
};

void Wait::doWwork() {
  while (run) {
    boost::system::error_code ec;
    timer_.wait(ec);
    io_service_.run();
    if (ec) {
      if (ec == boost::asio::error::operation_aborted) {
        // cleanup
      } else {
        // Something else, possibly nasty, happened
      }
    }
  }
}

void Wait::halt() {
  run_ = false;
  timer_.cancel();
}

Une fois que vous avez bien compris, asio est un outil formidable.

0
Nicole