Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

multithreading - Using a c++ class member function as a c callback function, thread safe version

The original question, got a great answer as to how to do the non thread safe version.

Here is the code, which I've tried to slightly modify to get to work:

#include <stdio.h>
#include <functional>
#include <thread>

void register_with_library(int (*func)(int *k, int *e)) {
   int x = 0, y = 1;
   int o = func(&x, &y);
}

typedef int (*callback_t)(int*,int*);

class A {
  template <typename T>
  struct Callback;

  template <typename Ret, typename... Params>
  struct Callback<Ret(Params...)> {
     template <typename... Args>
     thread_local static Ret callback(Args... args) {
        func(args...);
     }
     thread_local static std::function<Ret(Params...)> func;
  };
   public:
      A();
      ~A();
      int e(int *k, int *j);
    private:
      callback_t func;
};

template <typename Ret, typename... Params>
thread_local std::function<Ret(Params...)> A::Callback<Ret(Params...)>::func;

A::A() {
   Callback<int(int*,int*)>::func = std::bind(&A::e, this, std::placeholders::_1, std::placeholders::_2);
   printf("1.  C callback function ptr %p, C++ template function ptr %p Object ptr %p 
",func, Callback<int(int*,int*)>::func,  this) ;
   func = static_cast<callback_t>(Callback<int(int*,int*)>::callback);
   printf("2.  C callback function ptr %p
",func) ;
   register_with_library(func);
}

int A::e(int *k, int *j) {
   return *k - *j;
}

A::~A() { }

int main() {
   std::thread t1 = std::thread { [](){ A a;}};
   std::thread t2 = std::thread { [](){ A a;}};

   t1.join();
   t2.join();
}

The result is

function ptr 0x400eef
function ptr 0x400eef

How would one make this work properly to create new callbacks for each new object, considering I have multiple threads creating different objects?

EDIT:

As suggested by e.jahandar, using thread_local works to partially resolve the issue (only if there is 1 object created per thread). Thanks to this, Callback<int(int*,int*)>::func is allocated on a thread basis. Although, the issue persists with Callback<int(int*,int*)>::callback.

Without thread_local:

1. C callback function ptr 0x403148, C++ template function ptr 0x609180 Object ptr 0x7ff9ac9f3e60 
2. C callback function ptr 0x403673
1. C callback function ptr 0x4031a6, C++ template function ptr 0x609180 Object ptr 0x7ff9ad1f4e60 
2. C callback function ptr 0x403673

with thread_local :

1. C callback function ptr 0x403230, C++ template function ptr 0x7fc1ecc756d0 Object ptr 0x7fc1ecc74e20 
2. C callback function ptr 0x403701
1. C callback function ptr 0x4031d2, C++ template function ptr 0x7fc1ec4746d0 Object ptr 0x7fc1ec473e20 
2. C callback function ptr 0x403701
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If each thread just need one instance of specific object, you can use a global variable for object pointer with __thread storage class, __thread makes global variables unique to that thread.

Using monotonic class with static member for callback is another solution, like previous solution, you can use __thread for separating monothonic class instances for each thread.

Also be aware, __thread isn't standard thing

Edit

Here is an example

class.h

class someClass{
     private:
         someMethod(){ ... }
}

class.cpp

__thread void * objectPointer;

void initialize(){
    someClass * classPtr = new someClass();
    objectPointer = (void *) classPtr;
}

void * callbackFunction(void * args){
    someClass * obj = objectPointer;
    obj->someMethod();
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...