C# : Blocking a function call until condition met - c#

I am developing a C# Winforms application, part of the application will be uploading files to a webserver using AsyncUpload (using it,due to the need to use a porgress callback) , In the C# program
i got a simple for loop that calls The Uploading function
for(int i=0;i < 10 ; i++)
{
Uploadfun();
}
And the fun does some magic:
Uploadfun()
{
// Logic comes here
// webClient.UploadFileAsync runs a 2nd thread to perform upload ..
webClient.UploadFileAsync(uri, "PUT", fileNameOnHD);
}
And a callback that gets called when the Async upload is done
Upload_Completed_callback()
{
//Callback event
}
Edit
The logic sequence:
Fun gets called (from loop)
Fun logic is executed and done..
Goes back to for loop
Callback will be called eventually, when UploadFileAsync (which is running some logic in another thread) will end
The problem is on the 3rd point, when the execution moves back to the for loop, i need to block the loop from continuing until the callback get called.

So if I understand correctly, you want to call UploadFileAsync then block until the async call has hit your callback. If so, I'd use AutoResetEvent i.e
private readonly AutoResetEvent _signal = new AutoResetEvent(false);
fun()
{
// Logic comes here
// runs a 2nd thread to perform upload .. calling "callback()" when done
webClient.UploadFileAsync(uri, "PUT", fileNameOnHD);
_signal.WaitOne(); // wait for the async call to complete and hit the callback
}
callback()
{
//Callback event
_signal.Set(); // signal that the async upload completed
}
Using AutoResetEvent means that the state gets automatically reset after Set has been called and a waiting thread receives the signal via WaitOne

In C# methods block by default, so you shouldn't need to do anything. I'm assuming that for some reason you are calling a non-blocking method that starts a background task / thread / whatever and gives you a callback when it's done. You want to call this asynchonous method in a synchronous manner.
You can call fun from inside the callback. Something along these lines (pseudo-code):
int n;
callFunTenTimes()
{
n = 0;
fun(n);
}
callback()
{
++n;
if (n < 10)
fun(n);
else
print("done");
}
This is similar to continuation passing style.
An advantage to this method is that you can also make your method asynchronous without adding any extra threads, locks, or extra logic - you just supply a callback function which your client can subscribe to. It works well in an event-driven environment.

Zebrabox does have it right using a WaitHandle.
While Juliet's solution does work, the thread performing the spin-wait will consume a significant amount of processor in proportion to the WaitHandle, which would essentially be sitting idle.

The problem is here:
for(int i=0;i < 10 ; i++)
{
fun(); <-- if we block until this function finishes here, we stop the UI thread
}
What you're doing is sequential. And if you can't afford to block the UI thread, move the loop off the UI thread:
volatile downloadComplete;
void DownloadUpdates()
{
ThreadPool.QueueUserWorkItem(state =>
for(int i = 0; i < 10; i++)
{
downloadComplete = false;
webClient.UploadFileAsync(uri, "PUT", fileNameOnHD);
while(!downloadComplete) { Thread.Sleep(1); }
});
}
Upload_Completed_callback()
{
downloadComplete = true;
}
Now you can block the execution of the loop without halting your UI thread, and you also get the benefit of progress indicators from the webclient class.

Related

Semaphore in KeyUp event handler -- locks keyboard input

I'm trying to understand Semaphore's.
In short, I've placed a "long" running procedure (which accesses Network resources), InitializeNamesAsync("","",""), in a KeyUp event handler. I'm trying to allow the user to do continuous typing without slowdown while viewNames is being initialized by InitializeNamesAsync(). Since the user will be continuously typing, the KeyUp event handler will be called many times while the InitializeNamesAsync() method is running.
While the below code compiles fine, it locks up forever completely stopping keyboard input.
So my questions are:
is this an appropriate use of Semaphore's?
how can I make this work?
Is there a better way?
TIA
Having defined
ResourceLock = new Semaphore(0, 1);
private async void _cboLastName_KeyUpAsync(object sender, KeyEventArgs e)
{
if (viewNames == null)
{
ResourceLock.WaitOne();
await InitializeNamesAsync("", "", "");
ResourceLock.Release();
}
}
There's fundamental issue with your design, though you are using the Semaphore to allow multiple threads to enter and execute the event inside the critical region, but challenge is, which thread are you blocking?
As the event is executed on the Ui thread, which is just 1 and unique, what's happening is:
Your code enters the Event, Calls the WaitOne for the Semaphore on the Ui Thread and it's done you are blocked, it doesn't even execute the Async method as expected
Check the out the following Console code, what do you think is the result ?
Following code leads to Deadlock, since Ui or Main Console Thread is waiting upon itself
async Task Main()
{
Semaphore s = new Semaphore(0, 2);
for(int x = 0; x < 5;x++)
{
s.WaitOne();
await Test(x);
s.Release();
}
}
async Task Test(int x)
{
$"Entering : {x}".Dump();
await Task.Delay(3000);
}
In above code await Test(x); and s.Release(); are never called
What are the options, review modified design:
async Task Main()
{
for(int x = 0; x < 5;x++)
{
await Test(x);
s.WaitOne();
}
}
Semaphore s = new Semaphore(0,2);
async Task Test(int x)
{
$"Entering : {x}".Dump();
await Task.Delay(3000);
s.Release();
}
What's different here:
Async method was called before the Semaphore WaitOne is called
Semaphore Release happens post the finish of Async method, not on same thread (in this case on threadpool thread)
And you will find this code will execute successfully without any deadlock
What's the solution:
Don't call WaitOne on a unique thread like Ui thread, that's a recipe for deadlock, especially when Release is also scheduled on same thread
Call Release on a separate thread (I have used the Async method, which is using Threadpool thread in this case)
Other Details:
Ideally Semaphore is meant for the multiple threads to enter the critical region, if you are expecting only one thread, then Sempahore may not be the right choice, but it helps signaling threads unlike lock, you may also review ManualResetEvent and AutoResetEvent, which supports Signaling / EventWaitHandle use cases
The thread is blocked because you enter it twice and semaphore doesn't allow enter the same thread twice(while e.g. Monitor.Enter allows - but then it is not clear why would you need it here).
As I understand you need to launch initialization in the background.
Since it is UI thread you might not need to use synchronization primitives(in this case, at least, not in general). I think it would be enough just having two variables like
beingInitialized
and initialized with the code like
private async void EnsureInitialized()
{
if(!initialized && !beingInitialized)
{
beingInitalized = true;
await StartInitialization();
initalized = true;
beingInitialized = false;
}
}
And call it then as fire and forget
like
private async void _cboLastName_KeyUpAsync(object sender, KeyEventArgs e)
{
EnsureInitialized();
...

Is there any simple out of box infrastructure to execute action (event) in a main manager thread?

I would like to implement a main (manager) thread what starts multiple worker threads. The worker threads generate events, and calling back to the provided event handler. I would like to execute the event handlers in the main thread (serialized). (just like Control.Invoke executes the action in the thread in which the control was created)
I know this involves a message loop in the main manager thread, and a message queue in which the callbacks are serialized, please do not go into the details explaining this.
I do not want to reinvent the wheel, and implement this from scratch. Is there any in .NET out of box, or any light opensource implementation for this? (like concurrent pattern implementations or similar)
Please note: There is no GUI, just N+1 threads.
Thanks in advance
As an alternative to possible constructs in Task Parallel Library, you can achieve this through AutoResetEvent. Here is a very rough idea but you should be able to refine this. Main thread, after starting worker threads, would wait on AutoResetEvent. When a worker thread wants main thread to do something, it can set the AutoResetEvent instance and the main thread will continue.
Following is a simple example.
(At class level)
const int MaxThreads = 5;
AutoResetEvent[] _waitHandles = new AutoResetEvent[MaxThreads]; // one for each thread
ActionEnum[] _callbackActions = new ActionEnum[MaxThreads]; // one for each thread
object _callbackActionsLock = new object();
(Main thread)
for (int i = 0; i < MaxThreads; i++)
{
_waitHandles[i] = new AutoResetEvent(false);
}
// start 5 worker threads passing each thread its zero-based index...
// Wait loop:
for (int i = 0; i < MaxThreads; i++)
{
bool result = _waitHandles[i].WaitOne(500);
if (result)
{
PerformAction(i);
}
}
private void PerformAction(int i)
{
switch (_actions[i])
{
case Actions.CallbackA: ...
break;
case Actions.CallbackB: ...
break;
...
}
}
Worker threads can set and the wait handles like this
(worker thread)
// ... do some work
lock(_callbackActionsLock) // if no other thread will use this index of _callbackActions then no need for this lock
{
_callbackActions[currThreadIndex] = Actions.CallbackB;
}
_waitHandles[i].Set();
...

Need Observable timer to pass messages to UI thread

This code, called from the UI thread:
Jobs.Current.ShowProgress(_ =>
{
if (Jobs.Current.Duration == 0 && this.progressBarMarkJob.Value >= this.progressBarMarkJob.Maximum - this.progressBarMarkJob.Step / 2)
{
this.progressBarMarkJob.Step /= 2;
}
this.progressBarMarkJob.PerformStep();
}, () =>
{
stopwatch.Stop();
var elapsed = string.Format(stopwatch.Elapsed.TotalHours >= 1 ? #"{0:hh\:mm\:SS}" : #"{0:mm\:SS}", stopwatch.Elapsed);
this.labelMarkTime.Text = string.Format("Elapsed{0:8}", elapsed);
this.labelMarkTime.Visible = true;
Jobs.Current.Duration = (uint)stopwatch.Elapsed.TotalSeconds;
this.progressBarMarkJob.Value = this.progressBarMarkJob.Maximum;
});
where ShowProgress does:
public void ShowProgress(Action<long> notify, Action terminate)
{
this.Progress = Observable.Timer(ProgressInterval, ProgressInterval).Finally(terminate).Subscribe(notify);
}
blocks the UI thread completely, making it unresponsive.
If I insert .SubscribeOn(Scheduler.CurrentThread) before the Subscribe() call, it no longer blocks the UI thread. But then I get cross-thread exceptions, because the messages are not passed to the UI on the correct thread.
Is there a way to make that work so that I can get updates from the timer - leaving the UI responsive - that post back to the UI thread?
You need to add a call to ObserveOn(). If you use nuget package Rx-Xaml you can leverage ObserveOnDispatcher():
this.Progress = Observable.Interval(ProgressInterval)
.ObserveOnDispatcher()
.Finally(terminate)
.Subscribe(notify);
See my answer here to understand the difference between ObserveOn and SubscribeOn. Also, you don't supply the code for PerformStep() - I hope that it is fast and/or non-blocking.
I also replaced Timer with Interval as it saves you an argument.
Finally, presumably you are planning to dispose the subscription handle (this.Progress) when the job completes?

How to don't wait the function while it's working

I have function
void Search(string text) { ... }
Inside there are many SQLite queries like
List<Word> words = Database.connection.Table<Word>().Where(x => x.word == text).ToListAsync().Result;
And it's needed some time to complete this (about 3 sec).
At this moment interface is freezed.
It's not good. How to solve this problem and don't wait this function?
The bulk of your time is this bit of code
ToListAsync().Result
The LINQ statement itself does not do any work
xxx.Where(x => x.word == text)
until you request items from it. This can be either from a foreach statement, or a ToList statement. When you call ToListAsync you are requesting the work to be done asynchronously, which means that it will not tie up the UI thread. But then the .Result makes it synchronous. So, you are not taking advantage of the threading that is already provided. If you change the signature of the method and how you are getting the results, you'll be able to offload the work.
private async Task Search(string text)
{
// execute the LINQ query with the TPL
List<Word> words = await Database.connection.Table<Word>().Where(x => x.word == text).ToListAsync();
// we are back on the UI thread
foreach(Word word in words)
{
// do something
}
}
There is no need to create a BackgroundWorker or make your code more complex. If you are developing for Windows Phone 7, you'll want to add the Microsoft.Bcl.Async nuget package to your app.
A BackgroundWorker is a good class for a novice at using threads. It has a simple interface and can even provide feedback to feed a ProgressBar in the UI as the work progresses. You can find full details with examples in the How to use a background worker for Windows Phone page on MSDN. An example from the linked page:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
This is the method that gets run on the background thread. You can see that you even have the possibility to cancel the long running process at any time. The ReportProgress method is used to pass back a value representing the amount of work done.

Parallel.ForEach freezing on last loop [duplicate]

More newbie questions:
This code grabs a number of proxies from the list in the main window (I couldn't figure out how to make variables be available between different functions) and does a check on each one (simple httpwebrequest) and then adds them to a list called finishedProxies.
For some reason when I press the start button, the whole program hangs up. I was under the impression that Parallel creates separate threads for each action leaving the UI thread alone so that it's responsive?
private void start_Click(object sender, RoutedEventArgs e)
{
// Populate a list of proxies
List<string> proxies = new List<string>();
List<string> finishedProxies = new List<string>();
foreach (string proxy in proxiesList.Items)
{
proxies.Add(proxy);
}
Parallel.ForEach<string>(proxies, (i) =>
{
string checkResult;
checkResult = checkProxy(i);
finishedProxies.Add(checkResult);
// update ui
/*
status.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
status.Content = "hello" + checkResult;
}
)); */
// update ui finished
//Console.WriteLine("[{0}] F({1}) = {2}", Thread.CurrentThread.Name, i, CalculateFibonacciNumber(i));
});
}
I've tried using the code that's commented out to make changes to the UI inside the Parallel.Foreach and it makes the program freeze after the start button is pressed. It's worked for me before but I used Thread class.
How can I update the UI from inside the Parallel.Foreach and how do I make Parallel.Foreach work so that it doesn't make the UI freeze up while it's working?
Here's the whole code.
You must not start the parallel processing in your UI thread. See the example under the "Avoid Executing Parallel Loops on the UI Thread" header in this page.
Update: Or, you can simply create a new thread manuall and start the processing inside that as I see you have done. There's nothing wrong with that too.
Also, as Jim Mischel points out, you are accessing the lists from multiple threads at the same time, so there are race conditions there. Either substitute ConcurrentBag for List, or wrap the lists inside a lock statement each time you access them.
A good way to circumvent the problems of not being able to write to the UI thread when using Parallel statements is to use the Task Factory and delegates, see the following code, I used this to iterate over a series of files in a directory, and process them in a Parallel.ForEach loop, after each file is processed the UI thread is signaled and updated:
var files = GetFiles(directoryToScan);
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
Task task = Task.Factory.StartNew(delegate
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
Parallel.ForEach(files, currentFile =>
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
ProcessFile(directoryToScan, currentFile, directoryToOutput);
// Update calling thread's UI
BeginInvoke((Action)(() =>
{
WriteProgress(currentFile);
}));
});
}, tokenSource.Token); // Pass same token to StartNew.
task.ContinueWith((t) =>
BeginInvoke((Action)(() =>
{
SignalCompletion(sw);
}))
);
And the methods that do the actual UI changes:
void WriteProgress(string fileName)
{
progressBar.Visible = true;
lblResizeProgressAmount.Visible = true;
lblResizeProgress.Visible = true;
progressBar.Value += 1;
Interlocked.Increment(ref counter);
lblResizeProgressAmount.Text = counter.ToString();
ListViewItem lvi = new ListViewItem(fileName);
listView1.Items.Add(lvi);
listView1.FullRowSelect = true;
}
private void SignalCompletion(Stopwatch sw)
{
sw.Stop();
if (tokenSource.IsCancellationRequested)
{
InitializeFields();
lblFinished.Visible = true;
lblFinished.Text = String.Format("Processing was cancelled after {0}", sw.Elapsed.ToString());
}
else
{
lblFinished.Visible = true;
if (counter > 0)
{
lblFinished.Text = String.Format("Resized {0} images in {1}", counter, sw.Elapsed.ToString());
}
else
{
lblFinished.Text = "Nothing to resize";
}
}
}
Hope this helps!
If anyone's curious, I kinda figured it out but I'm not sure if that's good programming or any way to deal with the issue.
I created a new thread like so:
Thread t = new Thread(do_checks);
t.Start();
and put away all of the parallel stuff inside of do_checks().
Seems to be doing okay.
One problem with your code is that you're calling FinishedProxies.Add from multiple threads concurrently. That's going to cause a problem because List<T> isn't thread-safe. You'll need to protect it with a lock or some other synchronization primitive, or use a concurrent collection.
Whether that causes the UI lockup, I don't know. Without more information, it's hard to say. If the proxies list is very long and checkProxy doesn't take long to execute, then your tasks will all queue up behind that Invoke call. That's going to cause a whole bunch of pending UI updates. That will lock up the UI because the UI thread is busy servicing those queued requests.
This is what I think might be happening in your code-base.
Normal Scenario: You click on button. Do not use Parallel.Foreach loop. Use Dispatcher class and push the code to run on separate thread in background. Once the background thread is done processing, it will invoke the main UI thread for updating the UI. In this scenario, the background thread(invoked via Dispatcher) knows about the main UI thread, which it needs to callback. Or simply said the main UI thread has its own identity.
Using Parallel.Foreach loop: Once you invoke Paralle.Foreach loop, the framework uses the threadpool thread. ThreadPool threads are chosen randomly and the executing code should never make any assumption on the identity of the chosen thread. In the original code its very much possible that dispatcher thread invoked via Parallel.Foreach loop is not able to figure out the thread which it is associated with. When you use explicit thread, then it works fine because the explicit thread has its own identity which can be relied upon by the executing code.
Ideally if your main concern is all about keeping UI responsive, then you should first use the Dispatcher class to push the code in background thread and then in there use what ever logic you want to speedup the overall execution.
if you want to use parallel foreach in GUI control like button click etc
then put parallel foreach in Task.Factory.StartNew
like
private void start_Click(object sender, EventArgs e)
{
await Task.Factory.StartNew(() =>
Parallel.ForEach(YourArrayList, (ArraySingleValue) =>
{
Console.WriteLine("your background process code goes here for:"+ArraySingleValue);
})
);
}//func end
it will resolve freeze/stuck or hang issue

Categories

Resources