LuaPlus:如何从多线程C++;? 我在Lua脚本中有一种回调函数,我想从C++的不同线程调用(0到100次/秒)。到目前为止,它基本上是工作的,但只要我在很短的时间内多次调用它,它就会使程序崩溃,导致错误,如: -As???离子失败:0,文件…LuaFunction.h,第146行或(完全随机) 我认为这是在C++完成另一个任务之前从C++调用的。对我来说,最明显的尝试(lua函数调用期间,互斥锁锁定所有线程)根本没有帮助/ 如果我每2秒只调用Lua函数一次,那么我根本不会得到任何错误(好吧,在清理部分之前,如果它达到该点,它将崩溃而不会出现特定错误)
以下是我的代码(我尽量裁剪和简化代码,并添加了大量注释):LuaPlus:如何从多线程C++;? 我在Lua脚本中有一种回调函数,我想从C++的不同线程调用(0到100次/秒)。到目前为止,它基本上是工作的,但只要我在很短的时间内多次调用它,它就会使程序崩溃,导致错误,如: -As???离子失败:0,文件…LuaFunction.h,第146行或(完全随机) 我认为这是在C++完成另一个任务之前从C++调用的。对我来说,最明显的尝试(lua函数调用期间,互斥锁锁定所有线程)根本没有帮助/ 如果我每2秒只调用Lua函数一次,那么我根本不会得到任何错误(好吧,在清理部分之前,如果它达到该点,它将崩溃而不会出现特定错误),c++,function,callback,lua,luaplus,C++,Function,Callback,Lua,Luaplus,以下是我的代码(我尽量裁剪和简化代码,并添加了大量注释): 我对Lua的了解还不足以在Lua方面给你一个解决方案,但是这个问题的观点可能会帮助你解决这个问题 当您从Lua调用AddThread()时,会发生如下情况: 1. LuaState allocations 2. AddThread() execution 3. LuaState unwinding 当使用ThreadFunction()时 AddThread上没有互斥控制,因此在1/3和B/D之间可能会发生竞争情况。 但是,将互斥体添
我对Lua的了解还不足以在Lua方面给你一个解决方案,但是这个问题的观点可能会帮助你解决这个问题 当您从Lua调用AddThread()时,会发生如下情况:
1. LuaState allocations
2. AddThread() execution
3. LuaState unwinding
当使用ThreadFunction()时
AddThread上没有互斥控制,因此在1/3和B/D之间可能会发生竞争情况。
但是,将互斥体添加到AddThread并不能解决问题,因为它仍然会在1到3之间运行
如果仅在程序初始化时调用AddThread(),则可以在初始化完成之前阻止所有线程。如果在程序执行期间经常调用它,那么我将从单独的LuaState进行这些调用
[编辑]第二个想法:使用生产者/消费者的方法。那么C++线程就不需要运行Lua代码了。
C++建议:
//-- start Task.h --
struct Task{
static list<Task*> runningTasks;
static list<Task*> doneTasks;
static pthread_mutex_t mutex;
list<Task*>::iterator iterator;
virtual ~Task(){}
bool start(){
pthread_mutex_lock(&mutex);
bool hasSpace = runningTasks.size() < 100;
if(hasSpace){
runningTasks.push_front(this);
iterator = runningTasks.begin();
pthread_t unusedID;
pthread_create(&unusedID, NULL, Task::threadBody, this);
}
pthread_mutex_unlock(&mutex);
return hasSpace;
}
virtual void run() = 0;
virtual void processResults() = 0;
protected:
void finish(){
pthread_mutex_lock(&mutex);
runningTasks.erase(iterator);
doneTasks.push_front(this);
pthread_mutex_unlock(&mutex);
}
static void* threadBody(void* instance){
Task* task = static_cast<Task*>(instance);
task->run();
task->finish();
return NULL;
}
};
//-- end Task.h --
//-- start Task.cpp --
//Instantiate Task's static attributes
pthread_mutex_t Task::mutex;
list<Task*> Task::runningTasks;
list<Task*> Task::doneTasks;
//-- end Task.cpp --
struct SumTask: public Task{
int a, b, c;
void run(){
Sleep(3000);
c = a+b;
}
void processResults(){
LuaPlus::LuaFunction<int> CPP_OnMyEvent = pState->GetGlobal("LUA_OnMyEvent");
CPP_OnMyEvent(a,b,c);
}
}
//functions called by Lua
bool runSumTask(int a, int b){
SumTask task* = new SumTask();
task->a = a; task->b = b;
bool ok = task->start();
if(!ok)
delete task;
return ok;
}
int gatherResults(){
pthread_mutex_lock(&Task::mutex);
int totalResults = Task::doneTasks.size();
while(Task::doneTasks.size() > 0){
Task* t = Task::doneTasks.front();
Task::doneTasks.pop_front();
t->processResults();
delete t;
}
pthread_mutex_unlock(&Task::mutex);
return totalResults;
}
int main() {
//Must initialize/destroy Task::mutex
pthread_mutex_init(&Task::mutex, NULL);
//...
pthread_mutex_destroy(&Task::mutex);
}
lua状态不是线程安全的。不能同时从多个线程使用同一状态。你读过吗?@EtanReisner我不确定这是否真的适用于卢阿普勒斯。我还尝试为每个线程在LuaPlus state上创建,但根本不起作用。我认为一个新的LuaPlus状态基本上创建了一个新的脚本环境,而其他脚本环境是无法访问的。而且,互斥体的东西已经在我的代码中了,没有多大帮助。你能把调用从Lua上删除到AdToX(x,y),并从C++调用它吗?这将避免卡斯黛乐斯塔尼的大竞争问题。我可以将AdthToin函数封装到C++边上的另一个函数中,使包装函数可以用于Lua端,但我高度怀疑这会有什么区别,因为它们最终都必须导致pthRead创建()。为什么要在主循环中使用事件系统?我的程序的全部要点是它始终异步运行特定代码,所以我必须动态添加线程。我看不出有什么不同的实现方法。@Forivin Producer-consumer实际上是您所需要的。Lua在它自己的线程上,在无休止的阻塞调用循环中,给我下一个任务(),这个函数的C++端在共享队列上等待。好吧,我还不太理解代码,但我试着运行它,看看这是否是我要找的。。出现了很多错误。我能够解决大部分问题,但仍有一些问题我不太理解。我试图编译这个:但得到了这些错误:@Forivin Sry!我只有时间给你一个代码建议。无法真正编译它。现在我已经测试卡斯黛乐代码,并用一个工作版本更新了答案。@ S.RiGoCaseLalaNy代码仍然有一些问题,但这次我能够解决它们来编译它。但是,一旦我运行exe,就会出现“访问冲突”错误。下面是代码:下面是错误的屏幕截图:
1. LuaState allocations
2. AddThread() execution
3. LuaState unwinding
A. Mutex lock
B. LuaState allocations
C. LUA_OnMyEvent() execution
D. LuaState unwinding
E. Mutex Unlock
//-- start Task.h --
struct Task{
static list<Task*> runningTasks;
static list<Task*> doneTasks;
static pthread_mutex_t mutex;
list<Task*>::iterator iterator;
virtual ~Task(){}
bool start(){
pthread_mutex_lock(&mutex);
bool hasSpace = runningTasks.size() < 100;
if(hasSpace){
runningTasks.push_front(this);
iterator = runningTasks.begin();
pthread_t unusedID;
pthread_create(&unusedID, NULL, Task::threadBody, this);
}
pthread_mutex_unlock(&mutex);
return hasSpace;
}
virtual void run() = 0;
virtual void processResults() = 0;
protected:
void finish(){
pthread_mutex_lock(&mutex);
runningTasks.erase(iterator);
doneTasks.push_front(this);
pthread_mutex_unlock(&mutex);
}
static void* threadBody(void* instance){
Task* task = static_cast<Task*>(instance);
task->run();
task->finish();
return NULL;
}
};
//-- end Task.h --
//-- start Task.cpp --
//Instantiate Task's static attributes
pthread_mutex_t Task::mutex;
list<Task*> Task::runningTasks;
list<Task*> Task::doneTasks;
//-- end Task.cpp --
struct SumTask: public Task{
int a, b, c;
void run(){
Sleep(3000);
c = a+b;
}
void processResults(){
LuaPlus::LuaFunction<int> CPP_OnMyEvent = pState->GetGlobal("LUA_OnMyEvent");
CPP_OnMyEvent(a,b,c);
}
}
//functions called by Lua
bool runSumTask(int a, int b){
SumTask task* = new SumTask();
task->a = a; task->b = b;
bool ok = task->start();
if(!ok)
delete task;
return ok;
}
int gatherResults(){
pthread_mutex_lock(&Task::mutex);
int totalResults = Task::doneTasks.size();
while(Task::doneTasks.size() > 0){
Task* t = Task::doneTasks.front();
Task::doneTasks.pop_front();
t->processResults();
delete t;
}
pthread_mutex_unlock(&Task::mutex);
return totalResults;
}
int main() {
//Must initialize/destroy Task::mutex
pthread_mutex_init(&Task::mutex, NULL);
//...
pthread_mutex_destroy(&Task::mutex);
}
function LUA_OnMyEvent(a,b,c)
print(a.."+"..b.."="..c)
end
local totalRunning = 0;
for i=1, 999, 1 do
if (runSumTask(i,i*2))
totalRunning = totalRunning + 1;
totalRunning -= gatherResults();
end
while(totalRunning > 0) do
totalRunning -= gatherResults();
mySleepFunction(...);
end