来自 TCL C 线程和 TCL 脚本线程的 TCL 集 vwait 变量



我的C++应用程序嵌入了TCL(8.6.7),需要同时通过Windows命名管道(dll)和TCP套接字(TCL脚本)获取数据。我想使用TCL螺纹通过管道和插座实现同时数据采集。一个线程(threadPipe)通过TCL C api管理从命名管道读取的数据,另一个通过TCL脚本(threadTclSocket)的线程将管理套接字。主线程(C++应用程序)通过 TCL 脚本启动数据采集,并在其 TCL 脚本中使用vwait forever等待(非阻塞)工作线程。

我的问题:

  • 如何让我通过TCL脚本(threadTclSocket)获取TCL C线程(threadPipe)和线程来设置变量:主应用程序的forever何时完成,以便主线程可以退出其事件循环?
  • 我已经阅读了有关Tcl_ThreadQueueEventTcl_ThreadAlert的信息,但我不明白如何使用它们在主线程中设置变量forever

任何建议将不胜感激。

您可能应该使用 twapi 命名管道实现。我怀疑您的命名管道读取代码没有将其呈现为支持 tclfileevent异步 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。

在您的情况下,听起来您可能只是希望在事件过程中设置永久变量。

如果它有用,您可以看到整个文件。

但是,您确定不应该只在正确编写的命名管道通道上使用 fileevent 吗?

感谢您的所有建议,我已经解决了我的问题。

使用 TCL脚本设置vwait foreverforever变量非常简单,只需要使用forever作为thread::send的结果,让主 TCL 线程等待它。对于 TCL C 线程设置,forever立即在TCL_EventProc中挂起主 TCL 解释器。为了解决这个问题,我延迟了forever的设置,直到事件循环空闲,使用如下after

after idle {set forever thread}

最新更新