Убедитесь, что выделенная память принадлежит
Убедитесь, что каждая выделенная память принадлежит интеллектуальному указателю, либо auto_ptr в C ++ 03, unique_ptr в C ++ 11 или scoped_ptr в Boost, либо даже shared_ptr (который может использоваться совместно, копироваться и перемещаться) .
Таким образом, RAII защитит вас от любой утечки памяти.
Читать Вежливо прерывать , статья Херба Саттера, объясняющая разные способы прерывания потока.
Сегодня wth Boost.Thread 1.37 . Вы можете попросить завершить поток, выдав исключение. В Boost это исключение boost :: thread_interrupted, которое генерирует исключение из любой точки прерывания .
Таким образом, вам не нужно обрабатывать какой-либо цикл обработки сообщений или проверять некоторые глобальные / общие данные. Основной поток просит рабочий поток остановиться через исключение, и как только рабочий поток достигает точки прерывания, генерируется исключение. Механизм RAII, описанный ранее, обеспечит правильное освобождение всех выделенных данных.
Допустим, у вас есть некоторый псевдокод, который будет вызываться в потоке. Это может быть что-то вроде функции, которая, возможно, выделит память, и другая, которая будет выполнять много вычислений внутри цикла:
Object * allocateSomeObject()
{
Object * o = NULL ;
if(/*something*/)
{
// Etc.
o = new Object() ;
// Etc.
}
return o ; // o can be NULL
}
void doSomethingLengthy()
{
for(int i = 0; i < 1000; ++i)
{
// Etc.
for(int j = 0; j < 1000; ++j)
{
// Etc.
// transfert of ownership
Object * o = allocateSomeObject() ;
// Etc.
delete o ;
}
// Etc.
}
}
Приведенный выше код небезопасен и будет не зависеть от режима прерывания, если не будут предприняты шаги, чтобы быть уверенными, что в любой момент память будет принадлежать объекту C ++ (обычно это интеллектуальный указатель).
Можно изменить таким образом, чтобы код был как прерываемым, так и безопасным для памяти:
boost::shared_ptr<Object> allocateSomeObject()
{
boost::shared_ptr<Object> o ;
if(/*something*/)
{
// Etc.
boost::this_thread::interruption_point() ;
// Etc.
o = new Object() ;
// Etc.
boost::this_thread::interruption_point() ;
// Etc.
}
return o ; // o can be "NULL"
}
void doSomethingLengthy()
{
for(int i = 0; i < 1000; ++i)
{
// Etc.
for(int j = 0; j < 1000; ++j)
{
// Etc.
// transfert of ownership
boost::shared_ptr<Object> o = allocateSomeObject() ;
// Etc.
boost::this_thread::interruption_point() ;
// Etc.
}
// Etc.
boost::this_thread::interruption_point() ;
// Etc.
}
}
void mainThread(boost::thread & worker_thread)
{
// etc.
if(/* some condition */)
{
worker_thread.interrupt() ;
}
}
Не использовать Boost?
Если вы не используете Boost, вы можете смоделировать это. Имейте некоторую логическую переменную хранения потока, установленную в "true", если поток должен быть прерван. Добавьте функции, проверяющие эту переменную, а затем выдайте конкретное исключение, если оно истинно. Пусть «корень» вашего потока перехватит это исключение, чтобы оно правильно завершилось.
Ответственность
У меня сейчас нет доступа к Boost 1.37, поэтому я не могу протестировать предыдущий код, но идея есть. Я протестирую это как можно скорее и в конце концов опубликую более полный / правильный / компилируемый код.