непереносимой решение для POSIX-совместимых системах (например, Linux) будет использовать pthread_cancel()
, а затем pthread_join()
на native_handle()
члена подпиточного потока, который имеет тип pthread_t
(опять же, только на POSIX-совместимых систем. Я не могу говорить для других систем, таких как Windows).
Кроме того, вы должны использовать boost::scoped_thread
вместо просто boost::thread
так что вы можете «переопределить» (не в ОО-смысле) присоединиться к/отсоединять поведение, которые повышают будет делать, когда поток будет уничтожен. Это необходимо, потому что, когда вы вызываете pthread_cancel
, то pthread_join
на boost::thread
объект boost::thread
по-прежнему «соединяется» (то есть boost::thread::joinable()
возвращает true), и поэтому деструктор будет показывать неопределенное поведение на documentation.
С учетом всего сказанного, если в вашем приложении необходимо решение, зависящее от платформы для отмены таких потоков, я не уверен, что можно использовать многое из использования boost::thread
s по сравнению с обычным старым pthread
s; все же, я полагаю, для этого может быть и прецедент.
Вот пример кода:
// compilation: g++ -pthread -I/path/to/boost/include -L/path/to/boost/libs -lboost_thread main.cpp
#include <cstdio>
#include <pthread.h>
#include <boost/thread/scoped_thread.hpp>
typedef struct pthreadCancelAndJoin
{
void operator()(boost::thread& t)
{
pthread_t pthreadId = t.native_handle();
int status = pthread_cancel(pthreadId);
printf("Cancelled thread %lu: got return value %d\n", pthreadId, status);
void* threadExitStatus;
status = pthread_join(pthreadId, &threadExitStatus);
printf("Joined thread %lu: got return value %d, thread exit status %ld\n",
pthreadId, status, (long)threadExitStatus);
}
} pthreadCancelAndJoin;
void foo()
{
printf("entering foo\n");
for(int i = 0; i < 2147483647; i++) printf("f"); // here's your 'expensive computation'
for(int i = 0; i < 2147483647; i++) printf("a");
printf("foo: done working\n"); // this won't execute
}
int main(int argc, char **argv)
{
boost::scoped_thread<pthreadCancelAndJoin> t1(foo);
pthread_t t1_pthread = t1.native_handle();
sleep(1); // give the thread time to get into its 'expensive computation';
// otherwise it'll likely be cancelled right away
// now, once main returns and t1's destructor is called, the pthreadCancelAndJoin
// functor object will be called, and so the underlying p_thread will be cancelled
// and joined
return 0;
}
pthread_cancel()
отменит свой поток, когда он достигает «точки отмены» (если предположить, что cancel type and cancel state находятся в их значения по умолчанию, что в случае boost::thread
объектов); см. pthreads man page для списка всех пунктов отмены. Вы заметите, что эти точки отмены включают в себя многие из более общих системных вызовов, как write
, read
, sleep
, send
, recv
, wait
и т.д.
Если ваш «дорогой расчет» включает в себя любой тех (на примере кода printf
в конечном итоге вызывает write
), он будет отменен.
Прежде всего, Valgrind сообщает об утечке памяти или ошибках памяти с этим решением.
Наконец, заметка о вашем заблуждении в вашем вопросе:
я вычислял стыки будет рассматриваться как точка прерывания ...
join
, или любой из функции прерывания boost::thread
, если на то пошло, обрабатываются только как точка прерывания для потока, который звонит его. Поскольку ваш основной поток вызывает join()
, основной поток - это поток, который испытывает точку прерывания, а не поток, к которому он пытается присоединиться. Например. если вы вызываете thread1.interrupt()
в какой-то поток, а затем thread1
звонит thread2.join()
, то thread1
- тот, который прерван.
Канонический ответ: в сотрудничестве с потоком вы можете отменить его, используя любой способ, который он поддерживает. Без сотрудничества с нитью это невозможно. Даже не пытайтесь, это не сработает. (Вам нужно использовать процессы или какой-либо другой механизм. Нити не обеспечивают изоляцию.) –
У вас есть несинхронизированный доступ к 'thread1' и' thread2'. – curiousguy