2013-07-11 129 views
0

我正在为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.

+0

如果C++ 11是可能的话,则可以用成员函数启动std :: thread。请参阅http://stackoverflow.com/questions/10673585/start-thread-with-member-function – stefaanv

回答

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); 
    .... 
} 
+0

感谢您的解决方案! – DeniDoman

2

您需要将指向RS232的实例的指针传递给ReaderThread,wh ich将依次将该指针传递给static回调,或者直接调用RS232对象上的非static方法。我也会用[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); 
} 

更改您的回调函数使它也可以通过实例:

typedef int (*ReceivedCallback)(string data, RS232* that); 

而现在在callbac K优可以调用成员函数:

that->DoSomethingCool (data); 
+0

感谢您的帮助! – DeniDoman

1

要访问你可以使用这个非常哈克和未经考验的解决方案静态线程函数的非静态对象数据。但要注意---这只是为了教育目的,因为它非常黑客。您应该了解锁和互斥锁,并且可能会增强线程。请注意,这是一种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...... 
} 
+0

谢谢你有趣的解决方案! – DeniDoman