开发者

Thread cancellation (pthread) & C++

I'm writing MT program for Linux in C++ and I want to know how thread cancellation is performed.

As far as I understand when thread is cancelled cleanup functions are called inside thread's function and the thread's function is forced to exit. This mean two things:

  1. When thread is cancelled it still calls destructors fo all C++ objects created inside thread's function.
  2. I can pass to cleanup functions pointers to objects created in thread's function.

Am I right and code below ill work just fine?


One more question in code below, when thread is cancelled somewhere in SECTION A, second_thread_cleanup_function() will be called first, right?

class SomeObject
{
    public:
        ~SimpleObject (void); // <- free dynamically allocated mem开发者_运维问答ory

        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);
}


Destructors will only be called assuming you free allocated objects in the cleanup methods. Otherwise, no.

And yes, you have the order of cleanup calls in section A correct.


The assertion that a cancelled thread's stack is not unwound -- resulting in the non-destruction of local objects -- is inconsistent with the assertion by @Chris that the thread's stack is unwound and with the following counter-example:

#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();
}

When executed, the above program indicates that the local object's destructor is, indeed, called when the thread is cancelled:

$ ./a.out 
Obj() called
cleanup() called
~Obj() called
$ 


With any modern linux distribution using NPTL (which in practice means any running a 2.6 kernel), NPTL will call destructors and unwind the stack with a pseudo-exception.

In fact NPTL insists on it, by implementing what it calls forced stack unwinding. You can catch the pseudo-exception with catch(...), but if you do so you must subsequently rethrow it or the whole process will be terminated.

Chris

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜