[Closed] MAXScript | EXCEPTION_STACK_OVERFLOW The thread used up it's stack
Hey guys, excuse my ignorance in regards to MAXScript’s syntax. I have to give you a quick rundown on the task I was given, I’m attempting to execute 30 MAXScript commands per second for realtime feedback within 3dsMax. It works really well for like 7 secs, but freezes afterwards and gives me a runtime error saying
EXCEPTION_STACK_OVERFLOW The tread used up its stack
I’m guessing it’s talking about the main thread having multiple executions and it’s having trouble keeping up.
Btw, there’s a good chance “pyxms” is too slow from what I’ve heard. Is there a solution faster for setting values for custom attributes.
$Object.Custom_Attributes.ArmRaise = 0.555
Is there an equivalent to that command but using the SDK (MaxPlus)? And would it be significantly faster? ALSO, I tried using multithreading but apparently mxs doesn’t support multithreading, which really sucksss. I do not want to resort to learning C++ just for something like this lol. Thanks in advance
I don’t believe setting any reasonable number of cust attribute values can be slow. Only updating the data can slow down the process. So the solution could be the calling disablerefmsgs() before setting and enablerefmsgs() after.
Hey Denis, thanks for replying. I’ve tested “mxs.disablerefmsgs” and it didn’t seem to help out. Though I don’t know what it’s doing under the hood. Also, I forgot to mention that it’s not just one command, there’s over 30 commands setting 30 different custom attributes per second, so speed is crucial or it’ll over run the main thread. There has to be a way to use multithreading, or what’s the standard workflow for streaming and running commands into 3dsMax (realtime).
Right now, I’m using PySide2’s QThread as a Worker Thread to receive the data, and I’m using signals & slots to execute the command in the main thread. But for something like this, I would like to properly utilize multithreading like I do in other DCC softwares, unless there’s an alternative solution.
Here’s what the code looks like:
def on_command_received(self, message):
mxs.disableRefMsgs
mxs.execute("""try(undo off--
(with redraw off(%s))
undo off--
windows.processPostedMessages())catch
(print "Error Occured!"
windows.processPostedMessages())""" % (message))
mxs.enablerefmsgs
del (message)
mxs.gc()
mxs.clearUndoBuffer()
Keep in mind, “message” variable isn’t just one command, it’s multiple. So that means if there’s 60 setvalue commands and it takes like 0.008 secs to execute one of them, that’s a half sec, which is bound to cause issues.
I don’t know python, but shouldn’t it be like this?
def on_command_received(self, message):
mxs.disableRefMsgs()
mxs.execute( """ some mxs code """ ) % (message) )
mxs.enableRefMsgs()
Hey Serejah, yes thanks for calling that out. That’s exactly how the code is but I accidentally left it out. I’ll edit the post
you have to disable messages, set ALL values, and enable messages again. it only this way makes sense.
execute “mxs code” can be done in the main thread only
try() catch() is slow in MXS and also can be used in the main thread only
gc() is very slow operation and must never been used in a loop (or an event handler)
I can only see that you are definitely doing something wrong. But in order to understand what exactly and how to do it correctly, I must first of all know what you generally want to do using these callbacks (events). Unfortunately, this is not possible with the code you provided …
Hey Denis, I will show the rest of the code very soon. Thanks for the help so far, I see little improvements. I’m also convinced I’m doing something wrong lol
Hey, so here’s a majority of the algorithm, this algorithm is basically receiving data from a UDP socket/server on a separate thread, and then it sends it back over to the main thread (on_command_received() function) for execution.
####command_send = QtCore.Signal(str)
####data_values = UDPClientSocket.recvfrom(self.bufferSize)
####data_labels = #list of labels
value_index = 0
list_of_commands = []
for d in data_values:
if (value_index < len(self.data_labels)):
command = ("$Object.Custom_Attributes.%s = %s" % (self.data_labels[value_index], d))
list_of_commands.append(command)
value_index = value_index + 1
command = "\n".join(list_of_commands[1:])
time.sleep(1 / 24)
self.command_send.emit(str(command.encode('utf-8')))