使用C ++类成员函数作为C回调函数,线程安全版本 [英] Using a c++ class member function as a c callback function, thread safe version

查看:391
本文介绍了使用C ++类成员函数作为C回调函数,线程安全版本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

原始问题,效果很好回答如何制作非线程安全版本.

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 \n",func, Callback<int(int*,int*)>::func,  this) ;
   func = static_cast<callback_t>(Callback<int(int*,int*)>::callback);
   printf("2.  C callback function ptr %p\n",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();
}

结果是

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?

如e.jahandar所建议,使用thread_local可以部分解决该问题(仅当每个线程创建1个对象时).因此,Callback<int(int*,int*)>::func是基于线程分配的.虽然,此问题仍然存在Callback<int(int*,int*)>::callback.

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.

没有thread_local:

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:

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

推荐答案

如果每个线程只需要一个特定对象的实例,则可以使用__thread存储类为对象指针使用全局变量,__thread使全局变量对该线程唯一

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.

将具有静态成员的单调类用于回调是另一种解决方案,就像先前的解决方案一样,您可以使用__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.

还请注意,__thread不是标准的东西

Also be aware, __thread isn't standard thing

修改

这是一个例子

class.h

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

class.cpp

class.cpp

__thread void * objectPointer;

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

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

这篇关于使用C ++类成员函数作为C回调函数,线程安全版本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆