Recently I came across a proprietary third-party library and there is a method behave in this way:
public Point ClickOnDrawMat(DrawMat drwmat)
{
Point pt;
//waiting user mouse click on DrawMat and assign to pt
return pt;
}
When my code calling this method from main thread, it will block on this method until user clicks, then get the point return from ClickOnDrawMat
.
public void button1_Click(object sender, EventArgs e)
{
Point userClickedPoint = ClickOnDrawMat(oDrwMat); //Wait until user clicked
//Do stuff with point we got
}
However, it doesn't block the main thread. I still can press other button/UI control while it is still waiting for user click.
I noticed that upon waiting for user click, one of the CPU core usage seems pretty high (~75%).
And this is an example of the call stack after I click on another button while it still waiting for user click:
myProgram.frmMain.button2_Click(xxx) Line 23
[External Code]
ThirdPartyLib.ClickOnDrawMat(xxx) Line 16
myProgram.frmMain.button1_Click(xxx) Line 14
I am wondering how can this be done?
Thanks in advance!
If one user level thread performs blocking operation then entire process will be blocked. If one kernel thread perform blocking operation then another thread can continue execution.
Blocking vs non-blockingBlocking call waits for the I/O operation to complete before returning. Its results are returned synchronously. Nothing else in that process takes place during the waiting. In contrast, non-blocking call returns immediately without results and uses alternate means to check for completion.
Blocked means execution gets stuck there; generally, the thread is put to sleep by the system and yields the processor to another thread. When a thread is blocked trying to acquire a mutex, execution resumes when the mutex is released, though the thread might block again if another thread grabs the mutex before it can.
The send, receive, and reply operations may be synchronous or asynchronous. A synchronous operation blocks a process till the operation completes. An asynchronous operation is non-blocking and only initiates the operation.
We can't tell you exactly how it is done unless somone had a copy of the library and they use a decomplier to see what the code is doing (if you want to do it yourself dotPeek is free and easy to use).
However by how you describe its behavior it is likely repeatedly calling Application.DoEvents()
inside the function, this will let other messages be processed while the long running process is doing it's thing.
This is almost never a good coding practice for polling operations due to its high CPU cost, as you noticed, I recommend not doing it in your own code.
The "correct" way to handle this is use one of the Asynchronous Programming Patterns: the async/await feature added in .NET 4.5 or as a NuGet package for 4.0 (TAP), have the library raise an event of its own (EAP), or have the function use a callback function when it is finished (APM). Inside the function itself it should use a event driven system internally so that it does not use CPU power while it is waiting for an event to happen instead of polling.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With