pthread 是否可以调用同一个 class 中的 start_routine?

Is it possible for pthread to call a start_routine that is in the same class?

例如

class Foo
{
    void assingTask()
    {
        pthread_t myThread;
        int i;

        pthread_create(myThread, NULL, task, (void*) i)

    }

    void * task(void *val)
    {
        //DO Stuff
    }
};

我不断收到 'task' 不是静态函数的错误。我在网上看到的所有内容都提到有一个 find this。这些问题的解决方案远远超出了我的技能水平。谢谢你的帮助。

问题是 pthread_create 是一个 C 函数,而不是 C++ 函数,因此从 C++ 中使用它可能很棘手。第三个参数需要是一个 function 指针,但你试图用一个 method 指针调用它,这不是一回事。

C++ 确实允许将 static 方法指针隐式转换为函数指针,因此您可以用它做任何您想做的事(这就是为什么您会收到错误提示 'task' 不是静态的——因为如果是静态的,它可以转换为函数指针并使用)。通常你然后使用第 4 个参数来保存 "this" 这样你就可以从静态方法

调用非静态方法
class Foo
{
    void assingTask()
    {
        pthread_t myThread;
        int i;

        pthread_create(&myThread, NULL, start_task, this)

    }
    static void *start_task(void *this_) {
        return static_cast<Foo *>(this_)->task();
    }

    void * task()
    {
        //DO Stuff
    }
};

上面的代码有一个问题,你 "lose" pthread_t 句柄(不要将它存储在任何可访问的地方),所以你不能加入或脱离线程,但这可能可以通过多种方式修复。

当然可以。将您的数据放入结构中并将其包装在蹦床函数中以跳转到您的 class 函数:

#include <pthread.h>
#include <stdint.h>

class Foo;

// the context passed to trapoline function
struct FooTaskTrampolineCtx {
    Foo *obj;
    void *val;
};

extern "C" void *FooTaskTrampoline(void *ptr);

struct Foo {
    void assingTask() {
        pthread_t myThread;
        int i;
        // note - memory allocated dynamically
        struct FooTaskTrampolineCtx *c = new FooTaskTrampolineCtx;
        c->obj = this;
        c->val = (void*)(uintptr_t)i;
        pthread_create(&myThread, NULL, FooTaskTrampoline, c);
    }

    void * task(void *val) {
        //DO Stuff
    }
};

extern "C" void FooTaskTrampolineCleanup(void *ptr) {
    struct FooTaskTrampolineCtx *c = (struct FooTaskTrampolineCtx *)ptr;
    delete c;
}

// trampolines to task method
extern "C" void *FooTaskTrampoline(void *ptr) {
    struct FooTaskTrampolineCtx *c = (struct FooTaskTrampolineCtx *)ptr;
    void *ret = NULL;
    // remember to pick out the trash the PThread(TM) way
    pthread_cleanup_push(FooTaskTrampolineCleanup, ptr);
    ret = c->obj->task(c->val);
    pthread_cleanup_pop(1);
    return ret;
}