我的C ++应用程序嵌入了TCL(8.6.7),需要同时通过Windows命名管道(dll)和TCP套接字(TCL脚本)获取数据。我想使用TCL线程通过管道和套接字实现同步数据采集。一个线程(threadPipe)通过TCL C api管理从命名管道读取数据,另一个线程通过TCL脚本(threadTclSocket)管理套接字。通过TCL脚本的主线程(C ++应用程序)启动数据采集,并在其TCL脚本中使用vwait forever
等待(非阻塞)工作线程。
我的问题:
forever
当它们完成以便主线程可以退出它的事件循环?Tcl_ThreadQueueEvent
和Tcl_ThreadAlert
的内容,但我不明白它们如何用于在主线程中设置变量forever
。任何建议都将不胜感激。
答案 0 :(得分:2)
您应该使用twapi命名管道实现。我怀疑你的命名管道读取代码没有将其作为支持tcl fileevent
异步API的通道。如果您有这样的支持,如twapi版本中所见,那么您根本不需要额外的线程。您可以简单地使用fileevent
并在数据到达通道时调用一些tcl过程。
如果您继续使用现有代码,则使用Tcl_ThreadQueueEvent将事件发布到tcl通知程序,以便解释器线程在处理该事件时调用函数。这将控制转移到解释器线程。以下是我之前写过的一个例子:
static void MailslotSignalledProc(void *clientData)
{
MailslotData *slotPtr = (MailslotData *)clientData;
MailslotEvent *evPtr = NULL;
DWORD cbRead, cbSize = 0, cQueued = 0;
BOOL br = FALSE;
Tcl_GetLongFromObj(NULL, slotPtr->sizeObj, &cbSize);
GetOverlappedResult(slotPtr->handle, &slotPtr->ov, &cbRead, FALSE);
do
{
evPtr = (MailslotEvent *)ckalloc(sizeof(MailslotEvent));
evPtr->header.proc = EventProc;
evPtr->header.nextPtr = NULL;
evPtr->interp = slotPtr->pkgPtr->interp;
Tcl_Preserve(evPtr->interp);
evPtr->slotPtr = slotPtr;
evPtr->messageObj = Tcl_NewByteArrayObj(slotPtr->message, cbRead);
Tcl_IncrRefCount(evPtr->messageObj);
Tcl_ThreadQueueEvent(slotPtr->wait.tid, (Tcl_Event *)evPtr, TCL_QUEUE_TAIL);
/*
* Schedule another read on the mailslot. This may return
* immediately if data is already available. We also rate-limit
* by enforcing a wait after 64 immediate messages.
*/
br = ReadFile(slotPtr->handle, slotPtr->message, cbSize, &cbRead, &slotPtr->ov);
++cQueued;
} while (br && cQueued < 64);
Tcl_ThreadAlert(slotPtr->wait.tid);
return;
}
值得注意的是,我们有一个“继承”来自Tcl_Event的结构,并允许我们将自己的数据放入事件中。我们可以发布一些事件,并在完成后使用Tcl_ThreadAlert
唤醒目标。目标函数(在本例中为EventProc)将传递给这个结构,但是将在解释器线程上运行,所以我们必须记住Tcl_Obj引用计数。
在您的情况下,您可能只想在事件过程中设置永久变量。
如果有用,您可以看到whole file。
但是,您确定不应该在正确编写的命名管道通道上使用fileevent吗?
答案 1 :(得分:0)
感谢你的所有建议,我已经解决了我的问题。
使用TCL脚本设置forever
vwait forever
变量非常简单,只需使用forever
作为thread::send
的结果,并让主TCL线程等等。对于紧急在forever
中的TCL C线程设置TCL_EventProc
,挂起主TCL解释器。为了解决这个问题,我将forever
的设置延迟了,直到事件循环空闲时使用after
,如下所示:
after idle {set forever thread}