10

This is a generic question that I've always wondered.

In general, is it intensive for a CPU to create threads that perform "while not true ..." loops or similar?

For example, suppose I do:

// pseudo-code
new Thread(function() {
    while (!useHasDoneSomething) {
        // do nothing...
    }
    alert("you did something!");
}

So it's just a piece of code that runs in a thread that waits for something to happen.

For whatever reason I imagine that this would pressure the CPU. After all, even though it's just one little loop, it's re-running the loop the instant that a cycle is done. Wouldn't this mean that it's going through the cycle many times per millisecond? ... Per nanosecond!?

The operating system will "handle" the program and the thread(s), right? But that's still an awful lot of attention to running a loop. If the CPU has nothing else to do, wouldn't it just focus on that loop, thereby consuming all the idle time?

What if I create 1000 threads that all do the same loop? How might that affect performance/CPU cycles?

Furthermore, is this how events function internally? When you're 'listening' for an event in Java, .NET, Javascript etc (such as a button press or a window resize), has a thread that loops been created?

3
  • 1
    What the profiler tells you? May 22, 2013 at 4:52
  • 2
    My question is generic. Not so much a question of numbers but more "What's wrong with my understanding?" May 22, 2013 at 4:57
  • Got it. +1 then. May 22, 2013 at 5:01

4 Answers 4

13

In general, is it intensive for a CPU to create threads that perform "while not true ..." loops or similar?

Yes. Using such a loop is called busy waiting and it is called that for a reason. These busy loops check the condition as often and as fast as the processor can manage it, with the result that, if you stay in the loop long enough, the processor load goes reliably to 100%.

What if I create 1000 threads that all do the same loop? How might that affect performance/CPU cycles?

It only creates more work for the CPU doing noting.

Furthermore, is this how events function internally? When you're 'listening' for an event in Java, .NET, Javascript etc (such as a button press or a window resize), has a thread that loops been created?

No. Busy loops are a form of polling and a very inefficient one at that as well. Operating systems have other mechanisms to detect that an event has happened (e.g. an interrupt or a specific call) and they have mechanisms to let a thread wait for it without consuming CPU time. These mechanisms will also be used to implement the event mechanisms of languages like Java.

2
  • Thanks! What if you sleep the thread for short periods, maybe 100 milliseconds, during the loop? Would that slow the thread enough such that CPU cycles would not be wasted so often and therefore performance would recover? May 22, 2013 at 22:46
  • 2
    @RowanFreeman: It lessens the load on the processor, but it will still be higher than simply waiting for the OS to tell you that X has happened. May 23, 2013 at 6:44
9

Your instinct is correct. Busy-waiting like that is described as

Spinning can be a valid strategy in certain circumstances, most notably in the implementation of spinlocks within operating systems designed to run on SMP systems. In general, however, spinning is considered an anti-pattern and should be avoided, as processor time that could be used to execute a different task is instead wasted on useless activity.

Instead, you should consider a concurrency control primitive that allows the thread to truly go idle until it has useful work to do, for example a semaphore or a condition variable:

For many applications, mutual exclusion is not enough. Threads attempting an operation may need to wait until some condition holds true. A busy waiting loop, like

while not( condition ) do 
   // nothing
end

will not work, as mutual exclusion will prevent any other thread from entering the monitor to make the condition true. Other "solutions" exist. Such as having a loop that unlocks the monitor, waits a certain amount, locks the monitor and check for the condition P. Theoretically, it works and will not deadlock, but issues arise. It's hard to decide an appropiate amount of waiting time, too small and the thread will hog the CPU, too big and it will be apparently unresponsive. What is needed is a way to signal the thread when the condition P is true (or could be true). The solution is condition variables. Conceptually a condition variable is a queue of threads, associated with a monitor, on which a thread may wait for some condition to become true. Thus each condition variable is associated with an assertion . While a thread is waiting on a condition variable, that thread is not considered to occupy the monitor, and so other threads may enter the monitor to change the monitor's state. In most types of monitors, these other threads may signal the condition variable to indicate that assertion is true in the current state.

4
  • So is busy waiting much of a performance hit? Is a single loop (although firing constantly) any trouble at all? May 22, 2013 at 6:12
  • 1
    @RowanFreeman It is. Busy waiting, as the text suggests, keeps burning CPU cycles on useless instructions (ie, repeating if (!useHasDoneSomething) over and over, as fast as it can). Even if you don't mind it in your program, it wastes time that other programs could use to run. But even inside your program, a busy waiter wastes time that could be assigned to some worker thread (in case there aren't enough cores available for all threads to run simultaneously).
    – afsantos
    May 22, 2013 at 9:09
  • 2
    @afsantos There are valid uses for busy waiting - alternatives typically imply descheduling your thread and rescheduling it later. If you know you won't loop for more than a few CPU cycles, it can be much more efficient to busy-wait than to allow a context switch.
    – assylias
    May 22, 2013 at 9:26
  • 1
    @assylias Indeed, a context switch may be more of a performance hit, if it is known that the waiting time is very short. However, from my experience, busy waits are inappropriate more often than not. The OP would have to evaluate his individual case, to see if it is worth it or not.
    – afsantos
    May 22, 2013 at 10:41
2

Threads should wait for incoming events, not for variable changes.

Incoming events are semaphores becoming available, message queues becoming not empty or time elapsed:

semGet()
msqRead()
sleep()

From the thread point of view, these function calls are blocking: the thread waits until the event has come, leaving CPU load to other threads.

From the system point of view, the thread is marked as 'Waiting for event' and will not be scheduled as long as the event has not come.

About hardware events, they are handled through interrupts which are electric signals to the CPU and which trigger the execution of ISR (interrupt service routines), whose role is to produce a software event on semaphores, message queues or time.

0

The //do nothing part inside while condition in normal scenario is WAIT on some semaphore, or in other terms SLEEP. Sleep until some interrupt has woken you up. And hence the thread goes in "sleep state" or lets just say "not running state". Only the processes which are in running state consumes CPU. The sleep state process will not consume CPU. They may be consuming memory, but that memory will be swapped out internally by virtual memory system. So even if you create 1000 such threads they will not be posing much threat to your system.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.