如何在成员函数线程中调用回调?

时间:2013-07-11 12:59:08

标签: c++ multithreading oop serial-port

我正在为RS232端口编写小类。它可以同步写入和异步读取。因此,对于异步读取,我使用第二个线程,即等待输入数据。收到数据时,我想用输入数据调用用户回调(我得到的构造函数参数)。它看起来像:

typedef int (*ReceivedCallback)(string data);

class RS232
{
    RS232(string portName, ReceivedCallback dataReceived);
    ~RS232();

private:
    ReceivedCallback dataReceivedCallback;

private:
    static unsigned ReaderThread(void* data);

public:
    SendData(string data);
}

我的问题是:ReaderThread必须是静态的,以将指针传递给_beginthreadex()函数。在ReaderThread中我想调用“dataReceivedCallback”,从构造函数中的用户获取。但我不能,因为我无法在静态ReaderThread中调用非静态函数。另外,我不能使“dataReceivedCallback”静态,因为我可能有很多我的类实例(对于COM1,COM2,COM3),并且每个实例都应该有自己的回调,由用户获取。

我的架构错误在哪里?你会如何实现它?

提前致谢!

P.S。使用Visual Studio 2005。

3 个答案:

答案 0 :(得分:2)

您需要将指向RS232的实例的指针传递给ReaderThread,然后将该指针传递给static回调,或直接调用非{{ {1}}对象上的{1}}方法。

我还会使用static而不是RS232。我的代码示例将使用[CreateThread][1],但如果您愿意,可以将该技术调整为beginthreadex

简单地说,当开始CreateThread时,将指针传递给实例:

beginthreadex

...使用ReaderThread将其投回:

RS232* myObj = new RS232;
CreateThread (..., myObj);

更改回调函数,以便它也可以传递实例:

reinterpret_cast

现在在回调中你可以调用成员函数:

unsigned RS232::ReaderThread (void* data)
{
  RS232* that = reinterpret_cast <RS232*> (data);
}

答案 1 :(得分:1)

您需要将额外的参数传递给线程函数(您已经有void *data可用)。

现在,将其添加为class RS232中的私有元素:

class RS232
{

     RS232(string portName, ReceivedCallback dataReceived);
    ~RS232();

private:
    ReceivedCallback dataReceivedCallback;

private:
    static unsigned ReaderThread(void* data);

public:
    SendData(string data);
}

并在构造函数中:

RS232::RS232(string portName, ReceivedCallback dataReceived)
{
   ... various stuff to initialize the serial port ... 
   _beginthreadex(securityarg, stacksize, ReaderThread, this, ...)
}

在ReaderThread函数中:

unsigned RS232::ReaderThread(void *data)
{
   RS232 *self = static_cast<RS232*>(data);

   .... stuff to read from serial port ... 

   ... Now call the callback:
   self->dataReceivedCallback(str); 
   .... 
}

答案 2 :(得分:1)

要访问静态线程函数中的非静态对象数据,您可以使用这个非常hacky和未经测试的解决方案。但要注意 - 它仅用于教育目的,因为它非常黑客。您应该了解锁和互斥锁,并可能提升线程。注意,这是一种pthread风格的解决方案。我没有使用函数_beginthreadex()的经验,但你可以看到createThread完成了创建线程的工作。根据需要进行调整。

typedef int (*ReceivedCallback)(string data);

class RS232
{
public:
    RS232(string portName, ReceivedCallback dataReceived);
    ~RS232();
    SendData(string data);
    createThread();

private:
    ReceivedCallback dataReceivedCallback;
    static unsigned ReaderThread(void* data);
    thread m_someThread;

    struct accessHelper
    {
        RS232* This;
        void *actual_arg;
        accessHelper(RS232 *t, void *p)  
            : This(t), 
              actual_arg(p) 
              {}
    };

};

RS232::createThreaad()
{
     int someData;
     accessHelper ah(this, someData);
     m_someThread.create(RS232::ReaderThread, &ah);
}

RS232::ReaderThread(void *data) 
{
    accessHelper *ah = static_cast<accessHelper*>(data);
    RS232 *This = ah->This;
    This->dataReceivedCallback......
}