11

(the following items has different goals , but im interesting knowing how they "PAUSEd")

questions

Thread.sleep - Does it impact performance on a system ?does it tie up a thread with its wait ?

what about Monitor.Wait ? what is the difference in the way they "wait"? do they tie up a thread with their wait ?

what about RegisteredWaitHandle ? This method accepts a delegate that is executed when a wait handle is signaled. While it’s waiting, it doesn’t tie up a thread.

so some thread are paused and can be woken by a delegate , while others just wait ? spin ?

can someone please make things clearer ?

edit

http://www.albahari.com/threading/part2.aspx

enter image description here

Christian.K
  • 47,778
  • 10
  • 99
  • 143
Royi Namir
  • 144,742
  • 138
  • 468
  • 792

5 Answers5

8

Both Thread.Sleep and Monitor.Wait put the thread in the WaitSleepJoin state:

WaitSleepJoin: The thread is blocked. This could be the result of calling Thread::Sleep or Thread::Join, of requesting a lock — for example, by calling Monitor::Enter or Monitor::Wait — or of waiting on a thread synchronization object such as ManualResetEvent.

RegisteredWaitHandle is obtained by calling RegisterWaitForSingleObject and passing a WaitHandle. Generally all descendants of this class use blocking mechanisms, so calling Wait will again put the thread in WaitSleepJoin (e.g. AutoResetEvent).

Here's another quote from MSDN:

The RegisterWaitForSingleObject method checks the current state of the specified object's WaitHandle. If the object's state is unsignaled, the method registers a wait operation. The wait operation is performed by a thread from the thread pool. The delegate is executed by a worker thread when the object's state becomes signaled or the time-out interval elapses.

So a thread in the pool does wait for the signal.

Tudor
  • 61,523
  • 12
  • 102
  • 142
  • what about RegisteredWaitHandle – Royi Namir Jul 08 '12 at 08:44
  • I dont think you are right regards `RegisteredWaitHandle `: please see my edit. – Royi Namir Jul 08 '12 at 09:03
  • @Royi Namir: I think we are using a different terminology. I was not referring to how many threads are "tied up", but rather to whether the thread that does need to wait (even with `RegisteredWaitHandle`) is blocked or not. And it will be blocked until the `WaitHandle` is signaled. – Tudor Jul 08 '12 at 09:08
  • @Royi Namir: When you call `RegisterWaitForSingleObject` and pass a `WaitHandle`, somewhere inside the method a `Wait` is called, which is then complemented by the `Set` that you call manually to instruct the workers to begin work. Now, since the thread pool manages a limited number of threads, it's indeed likely that the workers don't wait themselves, but rather some dispatcher, but a thread somewhere is definitely put in `WaitSleepJoin` because that's how `WaitHandle` works. – Tudor Jul 08 '12 at 09:16
  • It's too bad we have no way of seeing the implementation of `ThreadPool`, because that would make things clear... – Tudor Jul 08 '12 at 09:18
  • @Royi Namir: I've added another snippet from the docs that should convince you. – Tudor Jul 08 '12 at 09:23
  • So youre saying that a thread is being blocked but noit a threadpool thread ? – Royi Namir Jul 08 '12 at 16:10
  • @Royi Namir: Basically the thread pool has a thread (not a worker) that waits on the signal and then dispatches work to available threads when the signal is set. – Tudor Jul 08 '12 at 16:14
  • is there any difference between thread (not a worker) to thread ( a worker) ? – Royi Namir Jul 08 '12 at 16:56
  • @Royi Namir: I don't think there is any structural difference (i.e. they are both standard threads), except that they are used for different purposes. – Tudor Jul 08 '12 at 17:02
  • @Royi Namir: Are you here a bit later? I'm about to go to dinner right now. – Tudor Jul 08 '12 at 17:38
  • great give me a pulse (lol) to namir.78@gmail.com ( i will get that immediatly on my iphone so i can go to chat). – Royi Namir Jul 08 '12 at 17:39
  • when you say thread wait , you mean 1 thread which is its job to wait , even if i have 40 threads which called RegisteredWaitHandle , there will still be 1 thread which check for signals and he's doing the actual wait ? ( and execute the callbacks) – Royi Namir Jul 08 '12 at 21:11
  • @Royi Namir: Yes, since there is a shared thread pool for the entire application, there is also a single thread that is doing the waiting, no matter how many threads are registering wait handles. – Tudor Jul 08 '12 at 21:26
  • what do you say about Joe answer ? if he says no threads are tie up - so this is the final answer. now the question is how the signal mechanism works ( while wait) – Royi Namir Jul 09 '12 at 04:53
  • 1
    @Royi Namir: His answer does not really contradict mine. As long as we don't have the actual implementation of `ThreadPool` we can only speculate based on the docs, which suggest that the pool has some thread that does the waiting. But in my opinion this is not relevant, because a single waiting thread is nothing to worry about. What is important is that: 1. no worker threads are wasted and 2. the current thread calling `RegisterWaitForSingleObject` is not blocked. – Tudor Jul 09 '12 at 09:08
6

Regarding ThreadPool.RegisterWaitForSingleObject, this does not tie up a thread per registration (pooled or otherwise). You can test this easily: run the following script in LINQPad which calls that method 20,000 times:

static ManualResetEvent _starter = new ManualResetEvent (false);

void Main()
{
    var regs = Enumerable.Range (0, 20000)
        .Select (_ => ThreadPool.RegisterWaitForSingleObject (_starter, Go, "Some Data", -1, true))
        .ToArray();

    Thread.Sleep (5000);
    Console.WriteLine ("Signaling worker...");
    _starter.Set();
    Console.ReadLine();

    foreach (var reg in regs) reg.Unregister (_starter);
}

public static void Go (object data, bool timedOut)
{
    Console.WriteLine ("Started - " + data);
    // Perform task...
}

If that code tied up 20,000 threads for the duration of the 5-second "wait", it couldn't possibly work.

Edit - in response to:

"this is a proof. but is there still a single thread which checks for signals only ? in the thread pool ?"

This is an implementation detail. Yes, it could be implemented with a single thread that offloads the callbacks to the managed thread pool, although there's no guarantee of this. Wait handles are ultimately managed by operating system, which will most likely trigger the callbacks, too. It might use one thread (or a small number of threads) in its internal implementation. Or with interrupts, it might not block a single thread. It might even vary according to the operating system version. This is an implementation detail that's of no real relevance to us.

Joe Albahari
  • 30,118
  • 7
  • 80
  • 91
  • thnaks for reply. this is a proof . but is there still a single thread which checks for signals only ? in the thread pool ? – Royi Namir Jul 09 '12 at 04:52
5

While it's true RegisterWaitForSingleObject creates wait threads, not every call creates one.

From MSDN:

New wait threads are created automatically when required

From Raymond Chen's blog:

...instead of costing a whole thread, it costs something closer to (but not exactly) 1/64 of a thread

So using RegisterWaitForSingleObject is generally preferable to creating your own wait threads.

Eli Arbel
  • 22,391
  • 3
  • 45
  • 71
  • HI , (ma kore ?) so creating RegisterWaitForSingleObject does creating wait threads , but we dont know how many ? so you think that the thred pool doesnt have a single thread which checks for signaling status ? and what does it mean 1/64 of a thread ? its a fraction.... please explain – Royi Namir Jul 09 '12 at 06:52
  • its related to threadpool, per 63 waithandle, it will issue a thread waiting at waitforany method. – TakeMeAsAGuest May 21 '18 at 16:03
3

ThreadPool.g RegisterWaitForSingleObject does call in its native implementation ultimately QueueUserAPC. See rotor sources (sscli20\clr\src\vm\win32threadpool.cpp(1981)). Unlike Wait Thread.Sleep your thread will not be put to a halt when you use RegisterWaitForSingleObject.

Instead for this thread a FIFO queue with user mode callbacks is registered which will be called when the thread is in an alertable state. That means you can continue to work and when your thread is blocked the OS will work on the registered callbacks giving your thread do to the opportunity to do something meaningful while it is waiting.

Edit1:

To complete the analysis. On the thread that did call RegisterWaitForSingleObject a callback is called on the thread when it is in an alertable state. Once this happens the the thread that did call RegisterWaitForSingleObject will execute a CLR callback that does register another callback which is processed by a thread pool callback wait thread which is only there to wait for signaled callbacks. This thread pool callback wait thread will then check in regular intervals for signaled callbacks.

This wait thread does finally call QueueUserWorkItem for the signalled callback to be executed on a thread pool thread.

Alois Kraus
  • 13,229
  • 1
  • 38
  • 64
  • From what I understood in the documentation of `RegisterWaitForSingleObject` a thread in the pool will actually wait for the handle to be signaled, but not necessarily the thread that actually does the work. – Tudor Jul 08 '12 at 09:32
  • so if i execute 50 times RegisteredWaitHandle , there will be still one "checking thread" which always check the signals state , but the other n-1 thread pool threads , are free from working , right ? – Royi Namir Jul 08 '12 at 21:09
  • Yes that is the idea behind all this. On Windows you can wait up to 64 (MAXIMUM_WAIT_OBJECTS) threads in one go. If you have more you will have an extra wait thread for every 64 threads. – Alois Kraus Jul 08 '12 at 22:06
3

Thread.Sleep and RegisteredWaitHandle work at different levels. Let me try and clear it up:

Processes have multiple threads, which execute simultaneously (depending on the OS scheduler). If a thread calls Thread.Sleep or Monitor.Wait, it doesn't spin - it is put to WaitSleepJoin state, and the CPU is given to other threads.

Now, when you have many simultaneous work items, you use a thread pool - a mechanism which creates several threads, and uses its own understanding of work items to dispatch calls to its threads. In this models, worker threads are called from the thread pool dispatcher to do some work, and then return back to the pool. If a worker thread calls a blocking operation - like Thread.Sleep or Monitor.Wait - the this thread is "tied up", since the thread pool dispatcher can't use it for additional work items.

I'm not familiar with the actual API, but I think RegisteredWaitHandle would tell the thread pool dispatcher to call a worker thread when needed - and your own thread is not "tied up", and can continue its work or return to the thread pool.

Jonathan
  • 6,939
  • 4
  • 44
  • 61