Search Unity

Engine keeps freezing due to a do-while loop

Discussion in 'Scripting' started by LO177, Jun 21, 2019.

  1. LO177

    LO177

    Joined:
    Jun 21, 2019
    Posts:
    2
    Was going to ask this on the Answers section, but for whatever reason it keeps breaking, so I'm posting here.

    Like the one thing I would think to use the Do-while loop instead of a regular while loop freezes the engine when pressing play :/

    Essentially I have the do-while loop set up, so that it would run once, regardless of whether the queue the while part checks for is actually null or not, and THEN have it check it. And I need it this way because the first time something will be added to the queue is within the loop itself.

    But even if I take out any enqueuing and dequeuing, all it does is crash, even though by logic, it should run the loop once, then do the check and have the loop end entirely. Adding something in just so the loop runs once as a while loop seems a tad bit stupid with me trying to trick the program to do my bidding. Anyway, here's the code:

    Code (csharp):
    1.  
    2.     Queue<Transform> selectionQueue = new Queue<Transform>();
    3.  
    4.     int depth = 0;
    5.  
    6.     do {
    7.         depth++;
    8.  
    9.        
    10.         if (depth > 12)
    11.         {
    12.             selectionQueue.Clear();
    13.         }
    14.     } while (selectionQueue != null);
    15.  
    ... Actually never mind, I tried having the queue have something set up in it before the loop goes through and the engine still freezes. I don't know what's going on here anymore, but commenting out the loop makes everything work just fine again.

    EDIT: I have applied necessary changes to code above. No change in behavior. Strange that the code wasn't encoded before, I believe I did try to figure out how to do it. Either way, I'd like to hear responses to the updated code. The code clearly states that after 12 loops, it should clear the queue and that should
     
    Last edited: Jul 14, 2019
  2. Zalosath

    Zalosath

    Joined:
    Sep 13, 2014
    Posts:
    687
    Is selectionQueue ever equal to null?
     
  3. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Whether you use a
    while
    loop or a
    do-while
    loop wouldn't make a difference here as you're creating an infinite loop regardless.
    You need to have a condition that breaks the loop at some point.

    This line here is setting a reference to your
    selectionQueue
    , meaning it's not null:
    Code (CSharp):
    1. Queue<Transform> selectionQueue = new Queue<Transform>();
    The loop's condition is checking if
    selectionQueue
    is not null:
    Code (CSharp):
    1. while (selectionQueue != null);
    The body of your loop is just incrementing some value that is unrelated to this condition:
    Code (CSharp):
    1. do {
    2.    depth++;
    3. }
    Therefore,
    selectionQueue
    will always be not null, causing an infinite loop.
     
    Last edited: Jun 21, 2019
  4. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Please use code tags, and you need to post the entire body of your loop if you want us to try to figure out what's wrong.

    (If that is the entire body of your loop, then your problem is that the loop's condition will never change from being true to being false as a result of anything that happens inside the loop, so the loop can never end. If your loop condition is based on the variable selectionQueue, then you need to be doing something with selectionQueue inside the loop.)
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,692
    @LO177 you make the queue object, it will be non-null. Checking for it to become null will never be true, unless your "depth" argument is a getter/setter that can set the queue to null.

    Even if you EMPTY the queue out, ie. remove all its elements, the object itself will still be non-null.

    And keep in mind at this level Unity is single-threaded, so if you're not setting the queue to null yourself in that loop, ain't nobody else on this green earth who will.
     
  6. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Just FYI, whenever I have a loop that I'm trying to debug why it gets into an infinite loop, I add something like this to avoid freezing the editor:

    Code (csharp):
    1. int loopCount = 0;  //declare a variable to count the number of loops
    2. while (true)  //I don't actually declare while loops like this, but just an obvious example of an infinite loop
    3. {
    4.     //Actual code here that I for some reason thought would end the loop, but is not
    5.  
    6.     loopCount++;  //increment the loop counter
    7.     if (loopCount > 10000)  //check for a ridiculously high number of loops compared to what I expected
    8.     {
    9.         Debug.Log("Hit infinite loop, breaking");
    10.         break;  //break the loop to avoid an editor freeze
    11.     }
    12. }
     
    Vryken and Kurt-Dekker like this.
  7. LO177

    LO177

    Joined:
    Jun 21, 2019
    Posts:
    2
    I have made an update on the code. Looks like I forgot to add a bit of code to how I was logically going to stop the loop. But even with the updated code (the if(depth > 12) statement added), it runs all the same, and by that I mean the engine still crashes as soon as I press enter, but logically it should exit the loop after 12 rounds. This is all the code that is running within the loop and it really confuses me as to why this doesn't change anything.

    And I know this code crashes the engine, as commenting out the loop runs the game like a charm.

    EDIT: turns out it requires me to define the list as null, despite the fact that it's empty to begin with. Is there any reason? And what would I check for if not for null just so I don't have to define the list as null after it has just been created? Some version of "undefined" or something else?
     
    Last edited: Jul 14, 2019
  8. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,108
    Man it's the basics.

    The variable and the object itself (in this case the queue) are separate entities altogether.
    If you set a variable with a constructor and don't set it to explicitly refer to a null, that means it still refers to an object.
    Whether you called Clear on that object has nothing to do with the fact that the variable is NOT null.
    You now simply have an empty collection.

    So you can't say things like this "turns out it requires me to define the list as null" -- you seem to not have the most basic of understanding for the underlying language.

    You're not defining the queue as null. The queue cannot be null. It's either the variable refers to a queue object, or it refers to null.
    Once again, when you clear a queue, you get an empty queue, there is no reason for the variable to auto-dereference itself from the object it used to refer to.

    If you want the variable to refer to a null, once you've cleared the queue (but there is absolutely no reason to clear it if you're simply releasing it to be destroyed), you need to set it to null explicitly.

    I know I'm a little annoying for having to repeat all of this so many times, but I hope I've explained it to you.

    If you're having issues with these kinds of things, I suggest you start from the beginning.
    First of all, it's just a convenience that you can define a queue and set it to a variable in one line.

    Because there are essentially two parts to it. One is to declare the variable, and the other is to construct the object and then assign it.

    So when you write

    Code (CSharp):
    1. List<int> myList = new List<int>();
    That's the same as

    Code (CSharp):
    1. List<int> myList;
    2. myList = new List<int>();
    I hope you can appreciate the subtle difference, even though it looks the same. The variable is independent from the object. When you use the '=' that's the moment where that variable starts to refer to an object. If it was a value type, it would behave differently and would contain a copy of it, but with objects it is always a reference. And it will hold that reference until you explicitly set it to some other object or null. And that is really important, because while any object is referenced like that, it cannot be garbage collected. Etc etc.

    If you have proper questions about the language start from its foundation.

    Btw, the solution in your case, if you really want to use Clear is to check the queue's Count property.

    Code (CSharp):
    1. do {
    2.   // whatever
    3.   if(...) queue.Clear();
    4. } while(queue.Count > 0)
    but the most obvious solution is simply to dereference the variable and release the object to be garbage cleaned.

    Code (CSharp):
    1. do {
    2.   // whatever
    3.   if(...) queue = null;
    4. } while(queue != null)
     
    Last edited: Jul 15, 2019
    Joe-Censored likes this.
  9. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,108
    Once again, full example

    It's either

    Code (CSharp):
    1. Queue<Transform> selectionQueue = new Queue<Transform>();
    2. int depth = 0;
    3.  
    4. do {
    5.   depth++;
    6.    
    7.   if (depth > 12)
    8.   {
    9.     selectionQueue = null;
    10.   }
    11. } while (selectionQueue != null);
    or

    Code (CSharp):
    1. Queue<Transform> selectionQueue = new Queue<Transform>();
    2. int depth = 0;
    3.  
    4. do {
    5.   depth++;
    6.    
    7.   if (depth > 12)
    8.   {
    9.     selectionQueue.Clear();
    10.   }
    11. } while (selectionQueue.Count > 0);
    Depending on what you're doing with the queue in the long-term, whether you're immediately instantiating a new one, etc. Sometimes it's better to recycle the existing one, and reuse it again for the same purpose, other then deallocating the old one and allocating memory for a new one. It's a waste of memory access.

    Oh and btw, this is much more readable imho, and works just as well

    Code (CSharp):
    1. Queue<Transform> selectionQueue = new Queue<Transform>();
    2. int depth = 0;
    3.  
    4. while(true) {
    5.   depth++;
    6.    
    7.   if (depth > 12)
    8.   {
    9.     selectionQueue.Clear();
    10.     break;
    11.   }
    12. }
     
  10. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,108
    I'm sorry for triple posting, but if you know you'll be counting to 12, why do you need the do-while loop at all?
    And what does this do anyway, is this just a snippet? It counts to 12 and then clears the queue without any side-effects.... Why not clear the queue immediately? Ok, I'll stop now and let you explain what's the general intention.