正如@sarnold 指出的那样,默认情况下,如果不调用任何作为取消点的函数,就无法使用pthread_cancel() 取消您的线程...但这可以通过使用pthread_setcanceltype() 将线程的取消类型设置为异步而不是延迟。为此,在开始循环之前,您需要在线程函数的开头附近添加类似pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); 的内容。然后您就可以通过从main() 调用pthread_cancel(th) 来终止线程。
但请注意,以这种方式取消线程(无论是否异步)不会清理线程函数中分配的任何资源(正如 Kevin 在评论中指出的那样)。为了干净利落地执行此操作,您可以:
- 确保线程在退出前不做任何需要清理的事情(例如,使用
malloc() 分配缓冲区)
- 确保在线程退出后其他地方的线程之后有某种方式进行清理
- 使用
pthread_cleanup_push() 和pthread_cleanup_pop() 添加清理处理程序,以便在取消线程时清理资源。请注意,如果取消类型是异步的,这仍然存在风险,因为线程可能在分配资源和添加清理处理程序之间被取消。
- 避免使用
pthread_cancel() 并让线程检查某些条件以确定何时终止(将在长时间运行的循环中检查)。由于您的线程随后会自行检查是否终止,因此它可以在检查后执行所需的任何清理工作。
实现最后一个选项的一种方法是使用互斥体作为标志,并使用封装在函数中的pthread_mutex_trylock() 对其进行测试,以便在循环测试中使用:
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
/* Returns 1 (true) if the mutex is unlocked, which is the
* thread's signal to terminate.
*/
int needQuit(pthread_mutex_t *mtx)
{
switch(pthread_mutex_trylock(mtx)) {
case 0: /* if we got the lock, unlock and return 1 (true) */
pthread_mutex_unlock(mtx);
return 1;
case EBUSY: /* return 0 (false) if the mutex was locked */
return 0;
}
return 1;
}
/* Thread function, containing a loop that's infinite except that it checks for
* termination with needQuit()
*/
void *thread_do(void *arg)
{
pthread_mutex_t *mx = arg;
while( !needQuit(mx) ) {}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t th;
pthread_mutex_t mxq; /* mutex used as quit flag */
/* init and lock the mutex before creating the thread. As long as the
mutex stays locked, the thread should keep running. A pointer to the
mutex is passed as the argument to the thread function. */
pthread_mutex_init(&mxq,NULL);
pthread_mutex_lock(&mxq);
pthread_create(&th,NULL,thread_do,&mxq);
sleep(2);
/* unlock mxq to tell the thread to terminate, then join the thread */
pthread_mutex_unlock(&mxq);
pthread_join(th,NULL);
sleep(2);
return 0;
}
如果线程没有被分离(默认情况下通常不是),你应该在停止线程后调用pthread_join()。如果线程是分离的,你不需要加入它,但你不会确切知道它何时终止(或者甚至大约,除非你添加另一种方式来指示它的退出)。