【问题标题】:C and Lua - Pass native object instance to native Lua functionC 和 Lua - 将原生对象实例传递给原生 Lua 函数
【发布时间】:2016-02-09 11:03:51
【问题描述】:

传递给 Lua 以便 Lua 可以调用本机函数的 C 函数是静态函数,因此与对象实例无关。

在我的应用程序中,我有多个会话。每个会话在自己的线程上运行,有自己的数据和脚本,会话 N 的脚本必须能够访问该会话 N 的数据。

问题在于,当您注册一个可从 Lua 调用的本机 C 函数时,我无法传递会话对象的实例以使其在静态 Lua 函数中可用。

一种可能是将会话实例存储到一个静态变量中,该变量可以从静态 C 函数调用(从 Lua 调用),但这看起来很脏,并且需要同步,这可能会导致某些脚本挂起。

第二种可能是创建一个表示会话的 Lua 对象并在其上调用成员方法,以便在我的 C 函数中,我可以访问表示会话的 Lua 对象(“t​​his”)和检索此对象表示的实际本机会话实例。但我不知道该怎么做。

有没有办法在 Lua 中创建表示本地对象实例的 Lua 对象,以便本地 Lua 函数可以访问该本地对象实例?

【问题讨论】:

  • 简单提示:“Lua”是一个名称,而不是首字母缩略词。这就是为什么它写成“Lua”,而不是“LUA”;)更多信息,请参阅lua.org/about.html#name :)

标签: c object static lua


【解决方案1】:

当你用 Lua 注册一个 C 函数时,你可以将附加值存储为所谓的“upvalues”。然后,C 函数可以在调用时检索这些值:

// ...
// push session instance pointer
lua_pushlightuserdata( L, (void*)get_current_session() );
// create a closure with one upvalue
lua_pushcclosure( L, my_static_C_function, 1 );
// ... (the resulting Lua function is at the stack top now)

在您的静态 C 函数中,您可以像这样访问实例数据:

static int my_static_C_function( lua_State* L ) {
  session_t* instance = (session_t*)lua_touserdata( L, lua_upvalueindex( 1 ) );
  instance->do_something();
  return 0;
}

【讨论】:

  • 这类似于我的答案中的最后一个解决方案,但“Lua-function-local”。如果他只需要一个函数的会话数据,这是一个很好的答案,否则 C 闭包会产生一些成本,并且将会话数据放入注册表更智能。
  • @siffiejoe 感谢您的帮助。这似乎接近我所需要的。我会继续阅读文档并使用它,除非我在阅读文档时找到更优雅的方式。
  • @Youka 为什么只有当我只需要从一个原生函数访问我的原生会话实例时,这个解决方案才会好?
  • @Virus721 没有上值的 Lua C 函数只是指向 C 函数(pure 函数)的指针。 closure 是另一种类型,必须在标头中管理上值。为每个函数创建、存储和 GC 相同的上值会在内存和性能方面付出代价。相反,注册表只需要一次创建,一个值的空间和堆栈销毁时的 GC。
  • @Virus721 此外,每个函数调用都需要准备上值(在堆栈旁边)。最后,您需要反复关注大量重复数据,而不是一个弱数据。
【解决方案2】:

既然每个会话都有自己的线程,为什么不将它们链接在一起呢? 无论何时调用您的函数,都从当前线程获取会话。

您可能需要查看有关用户数据的手册。

【讨论】:

  • 感谢您的帮助。尽管基于当前线程检索实例似乎不是很直接。如果我找不到更优雅的东西,我会保留这个解决方案。
  • 您可以使用 coroutine.thread() 将 C 函数包装在 Lua 中并在 Lua 端存储所需的数据。在 C 端做可能会更好,但在 Lua 端做也可以。调用 Func(...) 的代码实际上会调用 ActualCFunc(variableFromThread,...)
【解决方案3】:

由于“每个会话都在自己的线程上运行”,您可以简单地将会话数据保存为静态 thread-local

最好通过userdata 传输会话数据,metatable 绑定到关联函数,并且不要依赖静态内容。

作为最后一种选择,让我们组合:将会话数据保存为用户数据/指针Lua-state-local

在所有情况下,您都必须关心类实例的破坏,因为用户数据以 C 风格释放,与线程数据相同。

【讨论】:

  • 感谢您的帮助。我会尝试在此基础上做一些事情,并在文档中找到更多信息。我也不能使用本地线程,因为我使用 C++ 作为 Windows CE 和 Android 的通用代码库,并且我不能使用 C++11,因为我不能使用比 2008 年更新的 Visual Studio 版本。跨度>
猜你喜欢
  • 1970-01-01
  • 2019-03-23
  • 1970-01-01
  • 2017-07-21
  • 1970-01-01
  • 2015-09-25
  • 1970-01-01
  • 1970-01-01
  • 2013-04-14
相关资源
最近更新 更多