线程取消 (pthread) & C++
-
26-09-2019 - |
题
我正在用 C++ 为 Linux 编写 MT 程序,我想知道如何执行线程取消。
据我了解,当线程被取消时,会在线程的函数内部调用清理函数,并且线程的函数将被强制退出。这意味着两件事:
- 当线程被取消时,它仍然调用线程函数内创建的所有 C++ 对象的析构函数。
- 我可以将指向在线程函数中创建的对象的指针传递给清理函数。
我是对的吗,下面的代码工作得很好吗?
下面的代码中还有一个问题,当线程在某处被取消时 A 部分, 第二个线程清理函数() 会首先被调用,对吗?
class SomeObject
{
public:
~SimpleObject (void); // <- free dynamically allocated memory
void finalize (void);
// ...
}
void first_thread_cleanup_function (void* argument)
{
SomeObject* object (argument);
object->finalize ();
}
void second_thread_cleanup_function (void* argument)
{
// ... do something ...
}
void* thread_function (viod* argument)
{
SomeObject object;
pthread_cleanup_push (first_thread_cleanup_function, &object);
// ... some code ...
pthread_cleanup_push (second_thread_cleanup_function, NULL);
// ... SECTION A ...
pthread_cleanup_pop (0);
// .. some code ...
pthread_cleanup_pop (1);
}
解决方案
对于任何使用 NPTL 的现代 Linux 发行版(实际上意味着任何运行 2.6 内核的发行版),NPTL 将调用析构函数并使用伪异常展开堆栈。
事实上,NPTL 通过实现所谓的强制堆栈展开来坚持这一点。您可以使用 catch(...) 捕获伪异常,但如果这样做,您必须随后重新抛出它,否则整个过程将终止。
克里斯
其他提示
仅假设您在清理方法中释放了分配的对象,才会调用析构函数。否则,不行。
是的,A 部分中的清理调用顺序是正确的。
已取消线程的堆栈未展开的断言(导致本地对象不被破坏)与 @Chris 线程堆栈已展开的断言以及以下反例不一致:
#include <climits>
#include <iostream>
#include <pthread.h>
#include <thread>
#include <unistd.h>
class Obj {
public:
Obj() { std::clog << "Obj() called\n"; }
~Obj() { std::clog << "~Obj() called\n"; }
};
static void cleanup(void* arg) {
std::clog << "cleanup() called\n";
}
static void run() {
Obj obj{}; // Local object
pthread_cleanup_push(cleanup, nullptr);
::pause(); // Thread cancelled here
pthread_cleanup_pop(1);
}
int main(int argc, char **argv) {
std::thread thread([]{run();});
::sleep(1);
::pthread_cancel(thread.native_handle());
thread.join();
}
执行时,上面的程序表明本地对象的析构函数确实在线程被取消时被调用:
$ ./a.out
Obj() called
cleanup() called
~Obj() called
$
不隶属于 StackOverflow