Thread: simple while loop

  1. #16
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    There are generally only two cases where the loop condition needs to be checked, either at the beginnig (while) or the end (do-while). While there are some rare exceptions where you have to break out of a loop for some reason, you should usually rethink the use of a loop if you end up doing this all the time. using a lot of breaks inside an infinite while loop is just obfuscating the fact that you are using a goto loop, only a less readable one, since at least with goto you can 'find' for the label, whereas with while-break you have to manually search for the end of context.

  2. #17
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by abachler View Post
    using a lot of breaks inside an infinite while loop is just obfuscating the fact that you are using a goto loop, only a less readable one, since at least with goto you can 'find' for the label, whereas with while-break you have to manually search for the end of context.
    But that's why there are braces. You can easily see where a break will break the loop. Unless you're referring to something entirely different, I don't see how that is?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #18
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    > Such as the body

    Later perusal of the code can be problematic at points if the one doing the reading expects much of the logic of the loop condition to be defined on the header (as it should) and instead finds rules to be broken, altered or new ones being defined in the body.

    It's a matter of visibility just as CornedBee pointed out. Naturally breaks in a loop can be useful, but the context of this debate is that of breaks being placed where they could be replaced by a proper heading simply because the programmer is too confused (or lazy) by a complex conditional expression.

    In that context, breaks don't add anything. On the contrary they remove one important aspect; code readability. In the presence of the break, the reader still has to evaluate that new expression against the loop condition, just like they would do if it had been inserted in the loop header, sometimes several lines up in the code which doesn't help our already poor short-term memory. On the other hand, skimming through the code may result in missing the break altogether, missinterpreting it or erroneously evaluating its importance.

    EDIT: many complex logical expressions can be made easier to read by proper use of parenthesis and... lord, I'm sorry for what I'm about to say... commenting the code.
    Last edited by Mario F.; 02-01-2008 at 08:40 AM.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  4. #19
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    From what I see, if I see a break, I can think "oh, so if str == x, then the loop will break." Right there.
    If I see str != x as the condition, I need to scan the loop to see where that condition might occur, so I define it as more complex than breaks. For single expressions, it's alright, but when you get multiple expressions, it start getting complicated.
    As aside from when I see a break, I know that if x == NULL at this point, it will break, regardless of any other conditions. But if it's in the header, then I must evaluate, does the other condition also hold so that the loop will break?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #20
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    > As aside from when I see a break, I know that if x == NULL at this point, it will break, regardless of any other conditions. But if it's in the header, then I must evaluate, does the other condition also hold so that the loop will break?

    You will still have to evaluate the break expression against the header if you are bug-hunting, improving code performance (speaking of which you may want to look at your compiler documentation regarding this issue), or doing any other kind of code maintenance. Why else, would you want to look at old code?
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  6. #21
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Another good thing with break in body, is that I can easily control the conditions instead of thinking up a good loop condition such as, I need to make sure it breaks if this and this happens, but not that and then map that so it works with the code inside the loop.
    With breaks it's straight forward since you know if x == "1" at this point, then it must break.
    When writing some loops, I have no idea of what the condition must be, so I write an infinite loop and add breaks. Typically, if I wanted head conditions, I would have to go over that code and map it into a good header condition.

    Quote Originally Posted by Mario F. View Post
    You will still have to evaluate the break expression against the header if you are bug-hunting
    I never really have a clear image of what the head condition is. I always use the break-approach so I know it's going to break at this point. So I just need to evaluate the break expression to see if it's correct or not. Makes bug-hunting easier than complex head conditions.

    ...improving code performance (speaking of which you may want to look at your compiler documentation regarding this issue)
    Now that's unfortunately the drawback with the break-approach. But then I would use a profiler to see the bottlenecks and ponder how to optimize it.

    ...or doing any other kind of code maintenance.
    Maintenance is much easier with the break-approach
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #22
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    I shudder to imagine the kind of loop you write that you found your approach easier. Care to post an example?
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #23
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Hmmm. There may be more examples, but this one might do for a start. I shudder to think what would happen if I tried to make it header condition based. It's probably not possible:
    Code:
    for(;;)
    {
    	if (bCancel)
    	{
    		bCountCancel = true;
    		bFindCancel = true;
    		for(;;) // Must wait until threads complete
    		{
    			if (bCountFinished && bFindFinished) break;
    			Sleep(100);
    		}
    		DoCancel(i, pFiles);
    		goto Exit;
    	}
    	if (!bCountFinished && !bFindFinished) // None of threads are finished
    	{
    		CString strFormat;
    		Stuff::RequestData::CountFiles();
    		strFormat.Format(_T("Searching for files in the specified directory. Please wait. So far, &#37;I64u files has been found."), nTotalFiles);
    		m_Searching.SetWindowText(strFormat);
    		Sleep(500);
    		continue;
    	}
    	if (bCountFinished)
    	{
    		CString strFormat;
    		strFormat.Format(_T("Collecting files. Please wait. %I64u files were found."), nTotalFiles);
    		m_Searching.SetWindowText(strFormat);
    		Stuff::RequestData::FindFiles();
    		m_fProgress = (float)nCurrentFile / nTotalFiles * 100;
    		Sleep(100);
    	}
    	if (bFindFinished) break;
    }
    I'll see if I can find any better examples.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #24
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Holy spaghetti code, Batman!

    Well, you could start by doing
    Code:
    while(!bFindFinished) ...
    That would already greatly increase the readability for me.

    Then you could add && !bCancel to the condition and put the actual cancel handling code after the loop.

    Then you could split the loop into two parts, one for bCountFinished and one for not.

    Of course, with all the threading issues and global variables and polling, I'd just throw the entire thing away and write it from scratch.


    Anyway, this confirmed my suspicions. Basically, you want the loop to do too much, which is why you have such complex situations.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  10. #25
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    How about using do while for this:
    Code:
    do
    {
    	if (bCancel)
    	{
    		bCountCancel = true;
    		bFindCancel = true;
                    while(!(bCountFinished && bFindFinished))
    		{
    			Sleep(100);
    		}
    		DoCancel(i, pFiles);
    		goto Exit;
    	}
    	if (!bCountFinished && !bFindFinished) // None of threads are finished
    	{
    		CString strFormat;
    		Stuff::RequestData::CountFiles();
    		strFormat.Format(_T("Searching for files in the specified directory. Please wait. So far, %I64u files has been found."), nTotalFiles);
    		m_Searching.SetWindowText(strFormat);
    		Sleep(500);
    	} else if (bCountFinished)
    	{
    		CString strFormat;
    		strFormat.Format(_T("Collecting files. Please wait. %I64u files were found."), nTotalFiles);
    		m_Searching.SetWindowText(strFormat);
    		Stuff::RequestData::FindFiles();
    		m_fProgress = (float)nCurrentFile / nTotalFiles * 100;
    		Sleep(100);
    	}
    } while(!bCountFinished);
    Also changed a few other things, marked in red.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #26
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    What about this?
    Code:
    while (!bFindFinished && !Canceled)
    {
    	if (bCancel)
    	{
    		bCountCancel = true;
    		bFindCancel = true;
    		while (!bCountFinished || !bFindFinished) // Must wait until threads complete
    		{
    			Sleep(100);
    		}
    		DoCancel(i, pFiles);
    		Canceled = 1;
    	}
    	else if (!bCountFinished && !bFindFinished) // None of threads are finished
    	{
    		CString strFormat;
    		Stuff::RequestData::CountFiles();
    		strFormat.Format(_T("Searching for files in the specified directory. Please wait. So far, %I64u files has been found."), nTotalFiles);
    		m_Searching.SetWindowText(strFormat);
    		Sleep(500);
    	}
    	else if (bCountFinished)
    	{
    		CString strFormat;
    		strFormat.Format(_T("Collecting files. Please wait. %I64u files were found."), nTotalFiles);
    		m_Searching.SetWindowText(strFormat);
    		Stuff::RequestData::FindFiles();
    		m_fProgress = (float)nCurrentFile / nTotalFiles * 100;
    		Sleep(100);
    	}
    	/* else bFindFinished is true */
    }
    I think this works identically, but I didn't break out the formal proof.

  12. #27
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by CornedBee View Post
    Anyway, this confirmed my suspicions. Basically, you want the loop to do too much, which is why you have such complex situations.
    I agree with that.

    It may well _DO_ what you want, but it's not very nicely organized. And if I understand it right, the only reason you do all that in ONE loop, rather than two [one for counting, one for inserting] is that you want common cancellation - so perhaps you should put the cancel stuff in a function, and call that from either of the two loops?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #28
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by CornedBee View Post
    Holy spaghetti code, Batman!
    I know, I know. I typically just write the loop and don't give a crap about re-designing it later by looking over it and structuring a little better perhaps. A bad habit

    Of course, with all the threading issues and global variables and polling, I'd just throw the entire thing away and write it from scratch.
    I don't think I'd agree with that really. I've given it much thought.
    Tightly responsive GUI is very important to me, and I therefore believe that being able to cancel at any time is very important. I just hate those applications that seem to take an eternity to complete, freeze the GUI, give no choice to cancel, or just sits there eating up CPU and shows no visual feedback and when clicking cancel it just doesn't respond.

    Perhaps the blocking until the threads are complete could be put into a separate function, though. I just need to make sure they finish so I can kill the buffer I pass to it (since it's threaded!).

    Otherwise, I find the polling very ingenious. It will allow me to skip expensive locking and just a flag. If the flag is set, it will update progress into the correct variables and block until it's finished. So no race issues.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  14. #29
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    No, the polling is exactly the problem. Notifications should be pushed, not polled. For example, you shouldn't wait for the threads to finish by polling a global variable (without synchronization - is it a special atomic type?). You should do it by calling WaitForMultipleObjects(). Either on the threads themselves or, if they don't die, on event objects that get signalled when the threads are done.
    Actually you shouldn't loop at all. Rather, you should return to the message loop, and the threads should PostMessage() notifications whenever they've done a part of their job. You can update the UI in response. The same goes for cancellation, actually.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  15. #30
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by CornedBee View Post
    No, the polling is exactly the problem. Notifications should be pushed, not polled. For example, you shouldn't wait for the threads to finish by polling a global variable (without synchronization - is it a special atomic type?). You should do it by calling WaitForMultipleObjects(). Either on the threads themselves or, if they don't die, on event objects that get signalled when the threads are done.
    Here is how I did the polling:
    Code:
    namespace RequestData
    {
    
    void CountFiles() 
    {
    	ResetEvent(heRequestData_CountFiles);
    	bRequestData_CountFiles = true;
    	DWORD dw = WaitForSingleObject(heRequestData_CountFiles, 5000);
    	ASSERT(dw == WAIT_OBJECT_0);
    	//ResetEvent(heRequestData_CountFiles);
    }
    
    void FindFiles() 
    {
    	ResetEvent(heRequestData_FindFiles);
    	bRequestData_FindFiles = true;
    	DWORD dw = WaitForSingleObject(heRequestData_FindFiles, 5000);
    	ASSERT(dw == WAIT_OBJECT_0);
    	//ResetEvent(heRequestData_FindFiles);
    }
    
    }
    The idea is that the application should notify the threads that it wants the data (avoiding expensive locking and filling the buffers all the time), and so it sets resets an event, sets a flag to tell it wants the data and then waits for the event to be set again.
    The thread code itself will raise the event when it's done filling the information.

    Actually you shouldn't loop at all. Rather, you should return to the message loop, and the threads should PostMessage() notifications whenever they've done a part of their job. You can update the UI in response. The same goes for cancellation, actually.
    That's a good principle. However, I'm not sure how to actually implement it. The FindFiles function will loop and not provide any progress until I explicitly ask for it (for speed, for one thing). So in any case, there must be some code somewhere that tells it to update progress and perhaps send a message to the window.

    Quote Originally Posted by matsp View Post
    How about using do while for this:
    Also changed a few other things, marked in red.
    You may be right on that it works. I made a few changes. You're right that when looking at the loop again, a few things could easily be used as a head condition.

    Quote Originally Posted by tabstop View Post
    What about this?
    I think this works identically, but I didn't break out the formal proof.
    Your code is pretty much identical to what mats suggested except the cancel and goto. I put the goto there because it jumps to a common branch at the end of the function and does cleanup before returning control to the user and the GUI. That's why I use the goto. If you would just break the loop with cancel, I still have to do the cleanup or preparation and possible do a goto later instead.
    Last edited by Elysia; 02-01-2008 at 10:37 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. loop needed also how to make input use letters
    By LoRdHSV1991 in forum C Programming
    Replies: 3
    Last Post: 01-13-2006, 05:39 AM
  2. Trying to figure out a simple loop....
    By chadsxe in forum C++ Programming
    Replies: 9
    Last Post: 01-05-2006, 01:31 PM
  3. simple collision detection problems
    By Mr_Jack in forum Game Programming
    Replies: 0
    Last Post: 03-31-2004, 04:59 PM
  4. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  5. for loop or while loop
    By slamit93 in forum C++ Programming
    Replies: 3
    Last Post: 05-07-2002, 04:13 AM