简体   繁体   中英

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM