如何实现自定义 Tcl 事件循环?
How to implement custom Tcl event loop?
我看到了一些其他帖子,但它们都在 TCL 中,我希望在我的嵌入式解释器中使用 C++ 来执行此操作。我遇到的问题是我需要自己的事件循环,这样我就可以从网络上读取信息,在某些地方我可以检查套接字。我看到 Tcl_SetMainLoop() 但不确定它是如何工作的。
我的应用程序结构如下。
int Tcl_AppInit(Tcl_Interp *interp)
{
if (Tcl_Init(interp) == TCL_ERROR)
return TCL_ERROR;
if (MyTcl_Init(interp) == TCL_ERROR)
return TCL_ERROR;
return TCL_OK;
}
int main(int argc, char* argv[])
{
//...
Tcl_Main(argc, argv, Tcl_AppInit);
/* Replaced Tcl_Main for this, didn't work.
Tcl_SetMainLoop([]() {
Tcl_DoOneEvent(0);
});
*/
}
我不使用 Tk。关于如何设置自定义事件循环有什么想法吗?
如何在 Tcl 中进行事件循环的经典示例是 vwait
命令。其核心是这段代码:
done = 0;
foundEvent = 1;
while (!done && foundEvent) {
foundEvent = Tcl_DoOneEvent(TCL_ALL_EVENTS);
if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
break;
}
if (Tcl_LimitExceeded(interp)) {
Tcl_ResetResult(interp);
Tcl_SetObjResult(interp, Tcl_NewStringObj("limit exceeded", -1));
break;
}
}
done
变量由结束循环触发事件发生时的回调设置(写入变量),您自己的代码中可能会省略带有取消和限制管理的子句.精简版是:
done = 0;
foundEvent = 1;
while (!done && foundEvent) {
foundEvent = Tcl_DoOneEvent(TCL_ALL_EVENTS);
}
是的,它将大部分工作委托给 Tcl_DoOneEvent
(通知层的一部分)。如果您想将您喜欢的套接字插入其中,最简单的方法是编写您自己的事件处理程序并使用 Tcl_CreateFileHandler
or Tcl_CreateChannelHandler
安装它;可能是前者,假设您不在 Windows 上(因为它依赖于文件描述符的 POSIX 概念)并且在 Windows 上您需要做一些工作来制作频道类型(因为底层通知系统在该平台上的工作原理略有不同)。一旦你这样做了,你就可以使用标准的事件循环;您的自定义处理程序(在 C 或 C++ 中)将在正确的时间被调用。 (ClientData
参数实际上只是一个任意指针,它将通过 Tcl 不加解释地传递给您的回调;您可能会将其转换回指向真实对象类型的指针,作为您在回调中做的第一件事;这就是其他人所做的。)
可以使用Tcl_SetNotifier
安装您自己的低级事件处理引擎——如果您愿意,请尽早非常想那样做——但这通常是个坏主意。特别是,您不需要自定义事件循环来处理自定义套接字类型。自定义事件循环的更好用途是将 Tk 与其他一些 GUI 工具包集成,但这是一个 far 更复杂的用例!
我看到了一些其他帖子,但它们都在 TCL 中,我希望在我的嵌入式解释器中使用 C++ 来执行此操作。我遇到的问题是我需要自己的事件循环,这样我就可以从网络上读取信息,在某些地方我可以检查套接字。我看到 Tcl_SetMainLoop() 但不确定它是如何工作的。
我的应用程序结构如下。
int Tcl_AppInit(Tcl_Interp *interp)
{
if (Tcl_Init(interp) == TCL_ERROR)
return TCL_ERROR;
if (MyTcl_Init(interp) == TCL_ERROR)
return TCL_ERROR;
return TCL_OK;
}
int main(int argc, char* argv[])
{
//...
Tcl_Main(argc, argv, Tcl_AppInit);
/* Replaced Tcl_Main for this, didn't work.
Tcl_SetMainLoop([]() {
Tcl_DoOneEvent(0);
});
*/
}
我不使用 Tk。关于如何设置自定义事件循环有什么想法吗?
如何在 Tcl 中进行事件循环的经典示例是 vwait
命令。其核心是这段代码:
done = 0;
foundEvent = 1;
while (!done && foundEvent) {
foundEvent = Tcl_DoOneEvent(TCL_ALL_EVENTS);
if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
break;
}
if (Tcl_LimitExceeded(interp)) {
Tcl_ResetResult(interp);
Tcl_SetObjResult(interp, Tcl_NewStringObj("limit exceeded", -1));
break;
}
}
done
变量由结束循环触发事件发生时的回调设置(写入变量),您自己的代码中可能会省略带有取消和限制管理的子句.精简版是:
done = 0;
foundEvent = 1;
while (!done && foundEvent) {
foundEvent = Tcl_DoOneEvent(TCL_ALL_EVENTS);
}
是的,它将大部分工作委托给 Tcl_DoOneEvent
(通知层的一部分)。如果您想将您喜欢的套接字插入其中,最简单的方法是编写您自己的事件处理程序并使用 Tcl_CreateFileHandler
or Tcl_CreateChannelHandler
安装它;可能是前者,假设您不在 Windows 上(因为它依赖于文件描述符的 POSIX 概念)并且在 Windows 上您需要做一些工作来制作频道类型(因为底层通知系统在该平台上的工作原理略有不同)。一旦你这样做了,你就可以使用标准的事件循环;您的自定义处理程序(在 C 或 C++ 中)将在正确的时间被调用。 (ClientData
参数实际上只是一个任意指针,它将通过 Tcl 不加解释地传递给您的回调;您可能会将其转换回指向真实对象类型的指针,作为您在回调中做的第一件事;这就是其他人所做的。)
可以使用Tcl_SetNotifier
安装您自己的低级事件处理引擎——如果您愿意,请尽早非常想那样做——但这通常是个坏主意。特别是,您不需要自定义事件循环来处理自定义套接字类型。自定义事件循环的更好用途是将 Tk 与其他一些 GUI 工具包集成,但这是一个 far 更复杂的用例!