I've got a map that supports up to 14 players. Every time I've tested with 4-6 players, everything works fine. With more than that, I start to get "Too many threads" errors. I have two problems when it comes to troubleshooting this:
(1) I can't create these errors without getting more than 6 players in the game...I never see the errors when running the Test Document on local machine. It's tough to get 6 players to want to test your map.
(2) Since the Error Display seems to display only 4 rows at a time, I'm not sure if I'm seeing the end of a longer list of trigger errors when I view a replay...the errors happen on map start when banks are being loaded, UI items selected, and everything is getting initialized.
Is it possible to simulate players to see these errors? Is it possible to get a full list of Trigger Errors from a Replay or during runtime in battle.net? I feel like I don't have any tools for troubleshooting this issue. Any ideas about how to fix "Too many threads" errors would be much appreciated.
This is encountered when you have more than 256 (though I heard it was increased to 1024) triggers running at once. There is no excuse for this bar horrible triggering.
You should make sure all your triggers have proper events to stop them being created superfluously.
You should be able to just add computer players. If you don't include any special checks, most triggers should run for them just like for human players.
Also, the trigger debug window should be helpful, it shows the number of active threads.
If your triggers aren't all supposed to run constantly throughout the game you could try staggering them, one after the other. In other words, when trigger 1 is finished, add an action to run trigger 2. When trigger 2 is done, run trigger 3. So on and so forth.
Also look for duplicate events and combine these triggers using conditional branches or switches.
A new thread is created when:
- A trigger with the event "Map initialization" (or any event for that matter) is run.
- Running a trigger with the option "Don't wait until it finishes".
- Running an action which has the "Create thread" option on (this can be changed in the definition only, you cannot change it when you are actually calling an action).
It is safe to change the "Don't wait until it finishes" to a "Do wait until it finishes" when there are no wait instructions in the trigger you are about to run. Same for actions you have defined yourself.
Also there is a tool in the editor to allow you to see what threads are currently running. This can be enabled in the editor in:
File -> Preferences -> Test Document -> Enable "Run in windowed mode" AND enable "Show Trigger debugging window"
When testing the map (in the editor, not in battle.net), it should show a window which has a tab "Threads".
The problem might be that a lot of these threads disappear as soon as you started the map so keep that in mind.
Also this error suggests your looping on something very hard and kicking off more actions from the loop.
In the past I have encountered this error only while preforming custom threaded actions from a loop.
I found Sever things that can help prevent this error
use small waits in your loop to give the actions time to complete prior to kicking off another
remove unnecessary actions from your trigger and custom actions.
check the conditions and events related to the trigger creating the error to make sure it is not firing when it shouldn't be also that is it not firing multiple times
I've spent my fair share of time trying to fix these problems in my map.
First, for replicating it, I have a lot of things that will spawn for other players only if those players are in the game. I opted to use a boolean array variable "activePlayer" to set true or false for whether the player is in the game. I can simply force all slots to true and now the game will treat it as if it's a full game. This helped me produce a lot of these problems on my own, as well as giving me a lot more control over handling events with certain players losing or leaving.
Let's say you spawn 100 units, then wait 10 seconds and check to see if that unit is still alive. Within those 10 seconds you could spawn another 200 units and you'd now have 300 triggers running at once. This is a very simple example of how the problem can happen.
However, the problem is trickier than this! Some triggers, like "Unit enters region (entire map)" will cause this problem even if the unit does not meet the conditions. In my map i had about 30-40 different triggers with event "Unit enters region (entire map)", but most triggers were for specific unit types and would only be used for a few parts of the game.
While testing my map, I needed to catch the players up to mid-game, so i would instantly spawn 60 units for each player, six players, so 360 units total. Combined with the fact that each unit triggered the "Unit enters region (entire map)" for each of those triggers, i got a Too Many Threads error.
I solved this by making only one trigger with event "Unit enters region (entire map)", then i have blocks of if-then-else conditions to manually run the necessary triggers. If it's an enemy unit do one of 10 triggers, if it's friendly do one of 5 triggers, and then check for specific unit types that required these actions. You can run a trigger that has no event, and you can reference (triggering unit) within those manually run triggers. Perhaps if this is your problem, you could use a similar solution.
Why do you have threads running for all the units anyway? Couldn't you just use the Unit Dies event and do stuff with the units then? There should not be any reason to constantly run a thread per unit (or one for all units, for that matter); I am sure, there is an alternative solution. I personally use periodic checks or wait for condition actions only as a last resort and never in high quantities.
My problems are happening only at beginning of the game. I have quite a few UI elements and generally have 1 Trigger for each element. So when you click "Button X" the "Button X" trigger will run. As I'm going through creating all the dialogs and dialog items at the beginning of the game, it seems that having the system automatically Check and Select things for All Players is essentially running all of these triggers at once. I'm assuming that when I Select Item 1 of a Pulldown for (All Players), this runs the associated Trigger n times, where n is the number of players. I've tried to alleviate this by looping through each player and selecting things one at a time, with a wait between. This has gotten me a bit further, but I'm still seeing issues, so I just have to keep at it.
I am *not* seeing this behavior when I'm using computer players...I'm assuming the system is "smart enough" to not launch Triggers based on "Dialog Item is Used" event for non-human players. If someone could confirm, that would be appreciated.
I'm guessing this is because you got a lot of dialog items, each with events like Any button pressed for any player. For instance, if you have 50 buttons, each with its own trigger, then 50 triggers would be run each time a player presses a button - regardless of the conditions (they are checked at the start of the trigger). 6 players pressing a button at once would be 300 triggers then.
If that is your problem, I would recommend that you try to remove the events from your triggers, and instead add the events when you create the dialog items. That way you don't have to specify "any button", so only one trigger would be called when a player presses a button. You would need to use custom script for that though.
It is too many events, each event is a thread, combine all same events into one trigger and run functions from there.
Tofu runs 12 players at a time with no too many threads exceptions - yes I once got them, and it took a lot of refining of the script to reduce it down to zero, now I am running well within the limit. It comes down to how many events you have firing.
Is there any issue with keeping all the triggers separate and having one master trigger that calls all the other triggers (removing the Events from all the sub-triggers)? Or is it best to move all the code into one single trigger?
Also, what's the difference (threads/computation-wise) with specifying in the Run Trigger event that you want to Wait vs Not Wait for it to finish?
I began taking this approach and I'm finding that any trigger mentioned in any TriggerAddEventDialogControl() call will fire when any button in the game is clicked.
EDIT/SOLUTION: I needed to place these *after* the dialog items were created...seems to be working now.
Also, it seems in your post when you say "trigger" you sometimes mean "thread". For example, in the Debug window, I don't see 50 triggers running when I click a button. I only see the correct trigger. The threads window does not display output long enough for me to see anything, but I'm guessing that it's displaying 50 threads. I understand your point, but wanted to clarify the vocabulary. Please correct me if I'm wrong about this.
Is there any issue with keeping all the triggers separate and having one master trigger that calls all the other triggers (removing the Events from all the sub-triggers)? Or is it best to move all the code into one single trigger?
Also, what's the difference (threads/computation-wise) with specifying in the Run Trigger event that you want to Wait vs Not Wait for it to finish?
It doesn't matter if the code is moved or not, but you should be using Action Definition Functions (Which are basically a trigger with no event) rather than using the Run Trigger command, as I am not too sure if that creates a thread or not (ADF gives you more control anyway). But yes, if you move all your triggers with the same event into Action Definition functions and call those functions in the trigger, with different if/then switch conditions if you want to further reduce the amount of code running, then you should be able to remove all your errors.
This should work fine for time-based triggers but for triggers fired from a button press, for example, they sometimes need to get at context such as (Triggering Player). Unless there is a way to capture this info and pass through using TriggerAddEventDialogControl() on a dialog item, then I must continue to use triggers instead of ADRs for my dialog elements.
If ADFs are called in a trigger then they will indeed parse Triggering Player. Trust me it works, if you don't believe me try it. Because as a function within a trigger, it is basically like adding a block of code to the end of the trigger.
However, for good habit forming you should create a function with a parameter called "Player", and a local variable "Player" = parameter "Player".
That way you can call this in your trigger;
Function(Triggering Player)
And in the ADF, the local variable "Player" will be = Triggering Player.
See the 101 Thread at the top of this forum if you do not know how to add a parameter, or hit me up on Skype (PM me for info).
Some code from Tofu showing this in principle ... (I removed unrelated code and stuff so you can see exactly what I am talking about, this isn't a complete copy of the trigger just a one off example.)
I've got a map that supports up to 14 players. Every time I've tested with 4-6 players, everything works fine. With more than that, I start to get "Too many threads" errors. I have two problems when it comes to troubleshooting this:
(1) I can't create these errors without getting more than 6 players in the game...I never see the errors when running the Test Document on local machine. It's tough to get 6 players to want to test your map.
(2) Since the Error Display seems to display only 4 rows at a time, I'm not sure if I'm seeing the end of a longer list of trigger errors when I view a replay...the errors happen on map start when banks are being loaded, UI items selected, and everything is getting initialized.
Is it possible to simulate players to see these errors? Is it possible to get a full list of Trigger Errors from a Replay or during runtime in battle.net? I feel like I don't have any tools for troubleshooting this issue. Any ideas about how to fix "Too many threads" errors would be much appreciated.
This is encountered when you have more than 256 (though I heard it was increased to 1024) triggers running at once. There is no excuse for this bar horrible triggering.
You should make sure all your triggers have proper events to stop them being created superfluously.
You should be able to just add computer players. If you don't include any special checks, most triggers should run for them just like for human players.
Also, the trigger debug window should be helpful, it shows the number of active threads.
If your triggers aren't all supposed to run constantly throughout the game you could try staggering them, one after the other. In other words, when trigger 1 is finished, add an action to run trigger 2. When trigger 2 is done, run trigger 3. So on and so forth.
Also look for duplicate events and combine these triggers using conditional branches or switches.
A new thread is created when:
- A trigger with the event "Map initialization" (or any event for that matter) is run.
- Running a trigger with the option "Don't wait until it finishes".
- Running an action which has the "Create thread" option on (this can be changed in the definition only, you cannot change it when you are actually calling an action).
It is safe to change the "Don't wait until it finishes" to a "Do wait until it finishes" when there are no wait instructions in the trigger you are about to run. Same for actions you have defined yourself.
Also there is a tool in the editor to allow you to see what threads are currently running. This can be enabled in the editor in:
File -> Preferences -> Test Document -> Enable "Run in windowed mode" AND enable "Show Trigger debugging window"
When testing the map (in the editor, not in battle.net), it should show a window which has a tab "Threads".
The problem might be that a lot of these threads disappear as soon as you started the map so keep that in mind.
@jcraigk: Go
Also this error suggests your looping on something very hard and kicking off more actions from the loop.
In the past I have encountered this error only while preforming custom threaded actions from a loop.
I found Sever things that can help prevent this error
I've spent my fair share of time trying to fix these problems in my map.
First, for replicating it, I have a lot of things that will spawn for other players only if those players are in the game. I opted to use a boolean array variable "activePlayer" to set true or false for whether the player is in the game. I can simply force all slots to true and now the game will treat it as if it's a full game. This helped me produce a lot of these problems on my own, as well as giving me a lot more control over handling events with certain players losing or leaving.
Let's say you spawn 100 units, then wait 10 seconds and check to see if that unit is still alive. Within those 10 seconds you could spawn another 200 units and you'd now have 300 triggers running at once. This is a very simple example of how the problem can happen.
However, the problem is trickier than this! Some triggers, like "Unit enters region (entire map)" will cause this problem even if the unit does not meet the conditions. In my map i had about 30-40 different triggers with event "Unit enters region (entire map)", but most triggers were for specific unit types and would only be used for a few parts of the game.
While testing my map, I needed to catch the players up to mid-game, so i would instantly spawn 60 units for each player, six players, so 360 units total. Combined with the fact that each unit triggered the "Unit enters region (entire map)" for each of those triggers, i got a Too Many Threads error.
I solved this by making only one trigger with event "Unit enters region (entire map)", then i have blocks of if-then-else conditions to manually run the necessary triggers. If it's an enemy unit do one of 10 triggers, if it's friendly do one of 5 triggers, and then check for specific unit types that required these actions. You can run a trigger that has no event, and you can reference (triggering unit) within those manually run triggers. Perhaps if this is your problem, you could use a similar solution.
Why do you have threads running for all the units anyway? Couldn't you just use the Unit Dies event and do stuff with the units then? There should not be any reason to constantly run a thread per unit (or one for all units, for that matter); I am sure, there is an alternative solution. I personally use periodic checks or wait for condition actions only as a last resort and never in high quantities.
Thanks to all posters - valuable info here!
My problems are happening only at beginning of the game. I have quite a few UI elements and generally have 1 Trigger for each element. So when you click "Button X" the "Button X" trigger will run. As I'm going through creating all the dialogs and dialog items at the beginning of the game, it seems that having the system automatically Check and Select things for All Players is essentially running all of these triggers at once. I'm assuming that when I Select Item 1 of a Pulldown for (All Players), this runs the associated Trigger n times, where n is the number of players. I've tried to alleviate this by looping through each player and selecting things one at a time, with a wait between. This has gotten me a bit further, but I'm still seeing issues, so I just have to keep at it.
I am *not* seeing this behavior when I'm using computer players...I'm assuming the system is "smart enough" to not launch Triggers based on "Dialog Item is Used" event for non-human players. If someone could confirm, that would be appreciated.
I'm guessing this is because you got a lot of dialog items, each with events like Any button pressed for any player. For instance, if you have 50 buttons, each with its own trigger, then 50 triggers would be run each time a player presses a button - regardless of the conditions (they are checked at the start of the trigger). 6 players pressing a button at once would be 300 triggers then.
If that is your problem, I would recommend that you try to remove the events from your triggers, and instead add the events when you create the dialog items. That way you don't have to specify "any button", so only one trigger would be called when a player presses a button. You would need to use custom script for that though.
Edit:
Sorry - that was the wrong event. The correct one is
It is too many events, each event is a thread, combine all same events into one trigger and run functions from there.
Tofu runs 12 players at a time with no too many threads exceptions - yes I once got them, and it took a lot of refining of the script to reduce it down to zero, now I am running well within the limit. It comes down to how many events you have firing.
@DogmaiSEA: Go
Is there any issue with keeping all the triggers separate and having one master trigger that calls all the other triggers (removing the Events from all the sub-triggers)? Or is it best to move all the code into one single trigger?
Also, what's the difference (threads/computation-wise) with specifying in the Run Trigger event that you want to Wait vs Not Wait for it to finish?
@SBeier: Go
I began taking this approach and I'm finding that any trigger mentioned in any TriggerAddEventDialogControl() call will fire when any button in the game is clicked.
EDIT/SOLUTION: I needed to place these *after* the dialog items were created...seems to be working now.
Also, it seems in your post when you say "trigger" you sometimes mean "thread". For example, in the Debug window, I don't see 50 triggers running when I click a button. I only see the correct trigger. The threads window does not display output long enough for me to see anything, but I'm guessing that it's displaying 50 threads. I understand your point, but wanted to clarify the vocabulary. Please correct me if I'm wrong about this.
i thought this was for the site... which incidentally explodes when more than 256 threads are created...
'bout 2 to go... get ready for some noise :D
It doesn't matter if the code is moved or not, but you should be using Action Definition Functions (Which are basically a trigger with no event) rather than using the Run Trigger command, as I am not too sure if that creates a thread or not (ADF gives you more control anyway). But yes, if you move all your triggers with the same event into Action Definition functions and call those functions in the trigger, with different if/then switch conditions if you want to further reduce the amount of code running, then you should be able to remove all your errors.
@DogmaiSEA: Go
This should work fine for time-based triggers but for triggers fired from a button press, for example, they sometimes need to get at context such as (Triggering Player). Unless there is a way to capture this info and pass through using TriggerAddEventDialogControl() on a dialog item, then I must continue to use triggers instead of ADRs for my dialog elements.
If ADFs are called in a trigger then they will indeed parse Triggering Player. Trust me it works, if you don't believe me try it. Because as a function within a trigger, it is basically like adding a block of code to the end of the trigger.
However, for good habit forming you should create a function with a parameter called "Player", and a local variable "Player" = parameter "Player".
That way you can call this in your trigger;
Function(Triggering Player)
And in the ADF, the local variable "Player" will be = Triggering Player.
See the 101 Thread at the top of this forum if you do not know how to add a parameter, or hit me up on Skype (PM me for info).
Some code from Tofu showing this in principle ... (I removed unrelated code and stuff so you can see exactly what I am talking about, this isn't a complete copy of the trigger just a one off example.)
etc ... etc ...