Is it possible to show a wait message while a semaphore is locked in C#? - c#

I'm currently making a program to simulate a set of ATMs in visual C#. It's supposed to stop somebody accessing their account if it has already been accessed from a different location. Is it possible to show a message that the account has already been accessed while a semaphore is waiting?
Here is the part of the code where the semaphore is used:
private void button1_Click(object sender, EventArgs e)
{
count++;
if (count == 1)
{
account = findAccount();
if (findAccount() != 5)
{
textBox1.Text = "Please Enter Your Pin";
}
else
{
textBox1.Text = "Please Enter Your Account Number";
count = 0;
}
textBox2.Clear();
}
if (count == 2)
{
if (findPin(account) == true)
{
semaphore.WaitOne();
textBox1.Text = "1: Take Out Cash \r\n2: Balance \r\n3: Exit";
}
else
{
semaphore.Release();
textBox1.Text = "Please Enter Your Account Number";
count = 0;
}
textBox2.Clear();
}
if (count == 3)
{
atm();
}
if (count == 4)
{
withdraw();
}
if (count == 5)
{
int value = Convert.ToInt32(textBox2.Text);
customWithdrawl(value);
}
}

Consider doing two calls to WaitOne. The first call will have a timeout of zero and return a bool that will tell you whether or not you got the semaphore, or someone else still owns it. Two things can happen from there:
1) If someone else owns it, pop up a message that says "Someone else owns the semaphore" and call WaitOne again, but without a timeout (like you're doing now). After the 2nd call to WaitOne returns, close the window that you popped up a second ago..
2) If your call to waitOne with 0 timeout returns true, then you got the semaphore on the 1st try. No need to pop up a window.
Example:
if( semaphore.WaitOne(0) ) //This returns immediately
{
//We own the semaphore now.
DoWhateverYouNeedToDo();
}
else
{
//Looks like someone else already owns the semaphore.
PopUpNotification();
semaphore.WaitOne(); //This one will block until the semaphore is available
DoWhateverYouNeedToDo();
CloseNotification();
}
semaphore.Release();
Note, there are some other issues lurking here.
You probably want to use a try/finally block to release the semaphore to ensure that it gets released across all exception paths.
It's also probably a bad idea to call semaphore.WaitOne() from the GUI thread because the application will become non-responsive while it waits. In fact, you may not see the result of PopUpNotification() if you've hung the GUI thread while doing the 2nd Wait. Consider doing the long wait on a 2nd thread and raising an event back on the GUI thread once you own the semaphore
Consider the following design to resolve Issue 2:
private void button1_Click(object sender, EventArgs e)
{
if(AcquireSemaphoreAndGenerateCallback())
{
//Semaphore was acquired right away. Go ahead and do whatever we need to do
DoWhateverYouNeedToDo();
semaphore.Release()
}
else
{
//Semaphore was not acquired right away. Callback will occur in a bit
//Because we're not blocking the GUI thread, this text will appear right away
textBox1.Text = "Waiting on the Semaphore!";
//Notice that the method returns right here, so the GUI will be able to redraw itself
}
}
//This method will either acquire the semaphore right away and return true, or
//have a worker thread wait on the semaphore and return false. In the 2nd case,
//"CallbackMethod" will run on the GUI thread once the semaphore has been acquired
private void AcquireSemaphoreAndGenerateCallback()
{
if( semaphore.WaitOne(0) ) //This returns immediately
{
return true; //We have the semaphore and didn't have to wait!
}
else
{
ThreadPool.QueueUserWorkItem(new WaitCallback(Waiter));
return false; //Indicate that we didn't acquire right away
}
}
//Wait on the semaphore and invoke "CallbackMethod" once we own it. This method
//is meant to run on a background thread.
private void Waiter(object unused)
{
//This is running on a separate thread
Semaphore.WaitOne(); //Could take a while
//Because we're running on a separate thread, we need to use "BeginInvoke" so
//that the method we're calling runs on the GUI thread
this.BeginInvoke(new Action(CallbackMethod));
}
private void CallbackMethod()
{
textBox1.Text = string.Empty; //Get rid of the "Waiting For Semaphore" text. Can't do this if we're not running on the GUI thread
DoWhateverYouNeedToDo();
semaphore.Release();
}
Now, this solution could also be fraught with peril. It's kind of hard to follow the execution of the program because it jumps around from method to method. If you have an exception, it could be difficult to recover from and make sure all of your program state is correct. You also have to keep track of things like the account number and the pin numbers through all of these method calls. In order to do that, Waiter and CallbackMethod should probably take some parameter that tracks this state that gets passed along to each step. There's also no way to abort waiting (a time out). It will probably work, but shouldn't make it into any production code because it would be too difficult to maintain or extend.
If you really wanted to do it right, you should consider encapsulating the ATM logic in an object that will raise events that the GUI can subscribe to. You could have a method like ATM.LogInAsync(Account,Pin) that you could call. This method would return immediately, but some time later, an event on the ATM class like "LogInComplete" would fire. This event would have a custom EventArgs object that would contain data to trace which log-in has occurred (mainly the Account number). This is called the Event-based Asynchronous Pattern
Alternatively, if you're using C# 5.0, you can use the new Async/Await syntax in the AcquireSemaphoreAndGenerateCallback() method. That's probably the easiest way because the compiler will handle most of the complexities for you

Yes, you may show your message/form/messagebox right before the Wait method. Then when it receives the signal to unblock, you hide your message.

Related

Joining a worker thread in a windows forms app

My program works like this:
I press a radio button which opens the port.
Next i press a button "Read" which starts a thread that reads data continously from the Serial Port using port.ReadLine() and prints it in a textbox;
I have another radio which should first join the thread and after that close the port;the problem is the printing goes well until i close the port when the UI freezes.
public Form1()
{
mythread = new Thread(ReadFct);
myPort = new SerialPort("COM3", 9600);
myPort.ReadTimeout = 3500;
InitializeComponent();
foreach (var t in Constants.ComboParameters)
this.paramCombo.Items.Add(t);
radioClose.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
radioOpen.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
}
Below is the function attached to the thread
void ReadFct()
{
string aux = "";
while (readCondition)
{
if (myPort.IsOpen)
aux = myPort.ReadLine();
this.SetText(aux);
}
}
Below is the radio button event handler
public void radioButtonCheckedChanged(object sender,EventArgs e)
{
if (radioOpen.Checked && !myPort.IsOpen)
try
{
myPort.Open();
mythread.Start();
}
catch (Exception)
{
MessageBox.Show("Nu s-a putut deschide port-ul");
}
if (radioClose.Checked && myPort.IsOpen)
{
readCondition = false;
mythread.Join();
myPort.Close();
// myPort.DataReceived -= DataReceivedHandler;
}
}
The read button function:
private void readbtn_Click(object sender, EventArgs e)
{
if (!myPort.IsOpen)
MessageBox.Show("PORT NOT OPENED!");
else
{
// myPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
readCondition = true;
if (!mythread.IsAlive)
{
mythread = new Thread(ReadFct);
mythread.Start();
}
}
I have used what MSDN suggest when changing control from another thread:
private void SetText(string text)
{
if (this.textBox1.InvokeRequired)
{
StringTb del = new StringTb(SetText);
this.Invoke(del, new object[] { text });
}
else
SetData = text;
}
It's hard to know exactly what you need, lacking a good Minimal, Complete, and Verifiable code example to illustrate the question. That said, the issue here is that the Thread.Join() method causes that thread to stop doing any other work, and the thread you use to call that method is the thread that handles all of the user interface. Worse, if your port never receives another newline, the thread you're waiting on will never terminate, because you're stuck waiting on the ReadLine() method. Even worse, even if you do get a newline, if that happens while you're stuck waiting on the Thread.Join(), the call to Invoke() will deadlock, because it needs the UI thread to do its work, and the Thread.Join() call is preventing it from getting the UI thread.
In other words, your code has multiple problems, any one of which could cause problems, but all of which together mean it just can't possibly work.
There are a variety of strategies to fix this, but IMHO the best is to use await. The first step in doing that is to change your I/O handling so that it's done asynchronously instead of dedicating a thread to it:
// Ideally, you should rename this method to "ReadFctAsync". I am leaving
// all names intact for the same of the example though.
async Task ReadFct()
{
string aux = "";
using (StreamReader reader = new StreamReader(myPort.BaseStream))
{
while (true)
{
aux = await reader.ReadLineAsync();
// This will automatically work, because the "await" will automatically
// resume the method execution in the UI thread where you need it.
this.SetText(aux);
}
}
}
Then, instead of creating a thread explicitly, just create a Task object by calling the above:
public Form1()
{
// In this approach, you can get rid of the "mythread" field altogether
myPort = new SerialPort("COM3", 9600);
myPort.ReadTimeout = 3500;
InitializeComponent();
foreach (var t in Constants.ComboParameters)
this.paramCombo.Items.Add(t);
radioClose.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
radioOpen.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
}
public async void radioButtonCheckedChanged(object sender,EventArgs e)
{
if (radioOpen.Checked && !myPort.IsOpen)
{
try
{
myPort.Open();
await ReadFct();
// Execution of this method will resume after the ReadFct() task
// has completed. Which it will do only on throwing an exception.
// This code doesn't have any continuation after the "await", except
// to handle that exception.
}
catch (Exception)
{
// This block will catch the exception thrown when the port is
// closed. NOTE: you should not catch "Exception". Figure out what
// *specific* exceptions you expect to happen and which you can
// handle gracefully. Any other exception can mean big trouble,
// and doing anything other than logging and terminating the process
// can lead to data corruption or other undesirable behavior from
// the program.
MessageBox.Show("Nu s-a putut deschide port-ul");
}
// Return here. We don't want the rest of the code executing after the
// continuation, because the radio button state might have changed
// by then, and we really only want this call to do work for the button
// that was selected when the method was first called. Note that it
// is probably even better if you just break this into two different
// event handlers, one for each button that might be checked.
return;
}
if (radioClose.Checked && myPort.IsOpen)
{
// Closing the port should cause `ReadLineAsync()` to throw an
// exception, which will terminate the read loop and the ReadFct()
// task
myPort.Close();
}
}
In the above, I have completely ignored the readbtn_Click() method. Lacking a good MCVE, it's not clear what role that button plays in the overall scheme. You seem to have a radio button group (of two buttons) that control whether the port is open or closed. It is not clear why then you have an additional regular button that is seemingly able to also open the port and start reading, independently of the radio group.
If you want that extra button, it seems to me that all it ought to do is change the radio group state, by checking the "open" radio button. Then let the radio group buttons handle the port state and reading. If you need more specific advice as to how to fully integrate my code example above with your entire UI, you will need to provide more detail, preferably in a new question. That new question must include a good MCVE.

Threading: Waiting for window to open to do action

I have written a Window Manager for my program, which keeps certain windows open for the life of the Program (on background threads) (if the user wants them open).
I just implemented an action for the contacts window. The problem is that, the action works when the window is already open, but if the action is invoked when the window isn't open yet, then the window opens, but the action is not carried out (pressing the button again will carry out the action).
the code:
private static SetupContacts _contactsWindow;
private static Thread _contactthread;
public static void ShowContact(repUserObject uo, ContactFormAction action, int contactID)
{
if (_contactsWindow == null)
CreateContactThread(uo, contactID);
// make sure it is still alive
if (!_contactthread.IsAlive)
CreateContactThread(uo, contactID);
if (_contactsWindow != null)
{
_contactsWindow.BringToFront();
_contactsWindow.Focus();
switch (action)
{
case ContactFormAction.ViewContact:
if (contactID > 0)
_contactsWindow.LoadCustomer(contactID); // load the contact
break;
case ContactFormAction.AddNewContact:
_contactsWindow.AddCustomer();
break;
}
}
}
private static void CreateContactThread(repUserObject uo, int contactID)
{
if (_contactthread == null || !_contactthread.IsAlive)
{
_contactthread = new Thread(delegate()
{
_contactsWindow = new SetupContacts(uo, contactID);
_contactsWindow.CerberusContactScreenClosed += delegate { _contactsWindow = null; };
_contactsWindow.CerberusContactHasBeenSaved += delegate(object sender, ContactBeenSavedEventArgs args)
{
if (CerberusContactHasBeenSaved != null)
CerberusContactHasBeenSaved.Raise(sender, args);
};
Application.EnableVisualStyles();
BonusSkins.Register();
SkinManager.EnableFormSkins();
UserLookAndFeel.Default.SetSkinStyle("iMaginary");
Application.Run(_contactsWindow);
});
_contactthread.SetApartmentState(ApartmentState.STA);
_contactthread.Start();
}
}
What happens when the routine runs for the first time, (by calling ShowTime), that it hits the first if statement and goes to CreateContactThread() routine. That does it job, but when it returns, the _contactsWindow is still null. The next time the routine is called (ie, call by pressing the button the second time), it all works fine as the _contactWindow is not null.
How do i get it to do it all in one go ?
I am in vehement agreement with commenter Blorgbeard, who advises that it's a bad idea to run more than one UI thread. The API itself works best when used in a single thread, and many of the kinds of actions and operations one might want to do in code with respect to the UI objects are most easily handled in a single thread, because doing so inherently ensures things happen in the order one expects (e.g. variables are initialized before being used).
That said, if for some reason you really must run your new window in a different thread, you can synchronize the two threads so that the initial thread cannot proceed until the new thread has gotten far enough for the operations you want to perform on the newly-initialized object to have a reasonable chance of success (including, of course, that object having been created in the first place).
There are lots of techniques for synchronizing threads, but I prefer the new TaskCompletionSource<T> object. It's simple to use, and if and when you update the code to use async/await, it will readily mesh with that.
For example:
public static void ShowContact(repUserObject uo, ContactFormAction action, int contactID)
{
CreateContactThread(uo, contactID);
if (_contactsWindow != null)
{
_contactsWindow.BringToFront();
_contactsWindow.Focus();
switch (action)
{
case ContactFormAction.ViewContact:
if (contactID > 0)
_contactsWindow.LoadCustomer(contactID); // load the contact
break;
case ContactFormAction.AddNewContact:
_contactsWindow.AddCustomer();
break;
}
}
}
private static void CreateContactThread(repUserObject uo, int contactID)
{
if (_contactthread == null || !_contactthread.IsAlive)
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
_contactthread = new Thread(delegate()
{
_contactsWindow = new SetupContacts(uo, contactID);
_contactsWindow.CerberusContactScreenClosed += delegate { _contactsWindow = null; };
_contactsWindow.CerberusContactHasBeenSaved += delegate(object sender, ContactBeenSavedEventArgs args)
{
if (CerberusContactHasBeenSaved != null)
CerberusContactHasBeenSaved.Raise(sender, args);
};
_contactsWindow.Loaded += (sender, e) =>
{
tcs.SetResult(true);
};
Application.EnableVisualStyles();
BonusSkins.Register();
SkinManager.EnableFormSkins();
UserLookAndFeel.Default.SetSkinStyle("iMaginary");
Application.Run(_contactsWindow);
});
_contactthread.SetApartmentState(ApartmentState.STA);
_contactthread.Start();
tcs.Task.Wait();
}
}
Notes:
You had what appears to me to be redundant checks in your code. The CreateContactThread() method itself checks for null and !IsAlive, and restarts the thread if either of those are false. So in theory, by the time that method returns, the caller should be guaranteed that everything has been initialized as desired. And you should only have to call the method once. So I changed the code to do just that: call the method exactly once, and do so unconditionally (since the method will just do nothing if there is nothing to do).
The calling thread will wait in the CreateContactThread() method after starting the new thread, until the new window's Loaded event has been raised. Of course, the window object itself has been created earlier than that, and you could in fact release the calling thread at that time. But it seems likely to me that you want the window object fully initialized before you start trying to do things to it. So I've delayed the synchronization to that point.
As Blorgbeard has noted, one of the risks of running UI objects in multiple threads is that it's harder to access those objects without getting InvalidOperationExceptions. Even if it works, you should not really be accessing _contactsWindow outside of the thread where it was created, but the code above does just that (i.e. calls BringToFront(), Focus(), LoadCustomer(), and AddCustomer() from the original thread). I make no assurances that the code above is actually fully correct. Only that it addresses the primary synchronization issue that you are asking about.
Speaking of other possible bugs, you probably have an unresolved race condition, in that the new contacts-form thread might be exiting just as you are checking its IsAlive property. If you check the property just before it exits, but then try to access the thread and/or the window after it has exited, your code is likely to do something bad (like crash with an exception). This is yet another example of something that would be a lot easier to address if all of your UI objects were being handled in a single thread.
I admit that some of the above is speculative. It's impossible for me to say for sure how your code will behave without seeing a good, minimal, complete code example. But I feel the likelihood of all of the above being accurate and applicable is very high. :)

cancelling a backgroundworker with while loop

i know the common ways of cancelling a backgroundworker using eventwaithandles...
but i wanna know is that right to use a while loop to trap and pause working of a backgroundworker ? i coded like this :
Bool stop = false;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100000;
progressBar1.Value = 0;
for (int i = 0; i < 100000; i++)
{
progressBar1.Value++;
if (i == 50000)
stop = true;
while (stop)
{ }
}
}
private void button1_Click(object sender, EventArgs e)
{
stop = !stop;
}
Did you try it? What happened? Was it what you wanted to happen? Did you notice your computer's fans speeding up, to handle all the heat from your CPU in a tight, "do-nothing" loop?
Fact is, you should not "pause" a background task in the first place; if you don't it to keep running, interrupt it. If you want to be able to resume later, provide a mechanism to allow that. Even having your thread blocked efficiently waiting on a WaitHandle object would be the wrong thing to do, because it wastes a thread pool thread.
The code you've posted here is about the worst way to implement "pausing". Instead of waiting on some synchronization object such as a WaitHandle, you have the current thread just loop without interrupting, constantly checking the value of a flag. Even ignoring the question of whether you're using volatile (the code example doesn't show that, but then it also wouldn't compile, so…), it's terrible to force a CPU core to do so much work and yet get nowhere.
Don't pause your BackgroundWorker.DoWork handler in the first place. Really. Just don't do that. But if you insist, then at least use some kind of waitable object instead of a "spin-wait" loop as in the example you've posted here.
Here's an example of how your code might work if you wanted to avoid altogether tying up a thread while "paused". First, don't use BackgroundWorker, because it doesn't have a graceful way to do this. Second, do use await…that does specifically what you want: it allows the current method to return, but without losing track of its progress. The method will resume executing when the thing it waited on indicates completion.
In the example below, I've tried to guess at what the code that calls RunWorkerAsync() looks like. Or rather, I just assumed you've got a button2, which when clicked you call that method to start your worker task. If this is not enough to get you pointed in the right direction, please improve your question by including a good, minimal, complete code example showing what you're actually doing.
// These fields will work together to provide a way for the thread to interrupt
// itself temporarily without actually using a thread at all.
private TaskCompletionSource<object> _pause;
private readonly object _pauseLock = new object();
private void button2_Click(object sender, DoWorkEventArgs e)
{
// Initialize ProgressBar. Note: in your version of the code, this was
// done in the DoWork event handler, but that handler isn't executed in
// the UI thread, and so accessing a UI object like progressBar1 is not
// a good idea. If you got away with it, you were lucky.
progressBar1.Minimum = 0;
progressBar1.Maximum = 100000;
progressBar1.Value = 0;
// This object will perform the duty of the BackgroundWorker's
// ProgressChanged event and ReportProgress() method.
Progress<int> progress = new Progress<int>(i => progressBar1.Value++);
// We do want the code to run in the background. Use Task.Run() to accomplish that
Task.Run(async () =>
{
for (int i = 0; i < 100000; i++)
{
progress.Report(i);
Task task = null;
// Locking ensures that the two threads which may be interacting
// with the _pause object do not interfere with each other.
lock (_pauseLock)
{
if (i == 50000)
{
// We want to pause. But it's possible we lost the race with
// the user, who also just pressed the pause button. So
// only allocate a new TCS if there isn't already one
if (_pause == null)
{
_pause = new TaskCompletionSource<object>();
}
}
// If by the time we get here, there's a TCS to wait on, then
// set our local variable for the Task to wait on. In this way
// we resolve any other race that might occur between the time
// we checked the _pause object and then later tried to wait on it
if (_pause != null)
{
task = _pause.Task;
}
}
if (task != null)
{
// This is the most important part: using "await" tells the method to
// return, but in a way that will allow execution to resume later.
// That is, when the TCS's Task transitions to the completed state,
// this method will resume executing, using any available thread
// in the thread pool.
await task;
// Once we resume execution here, reset the TCS, to allow the pause
// to go back to pausing again.
lock (_pauseLock)
{
_pause.Dispose();
_pause = null;
}
}
}
});
}
private void button1_Click(object sender, EventArgs e)
{
lock (_pauseLock)
{
// A bit more complicated than toggling a flag, granted. But it achieves
// the desirable goal.
if (_pause == null)
{
// Creates the object to wait on. The worker thread will look for
// this and wait if it exists.
_pause = new TaskCompletionSource<object>();
}
else if (!_pause.Task.IsCompleted)
{
// Giving the TCS a result causes its corresponding Task to transition
// to the completed state, releasing any code that might be waiting
// on it.
_pause.SetResult(null);
}
}
}
Note that the above is just as contrived as your original example. If all you had really was a simple single loop variable iterating from 0 to 100,000 and stopping halfway through, nothing nearly so complicated as the above would be required. You'd just store the loop variable in a data structure somewhere, exit the running task thread, and then when you want to resume, pass in the current loop variable value so the method can resume at the right index.
But I'm assuming your real-world example is not so simple. And the above strategy will work for any stateful processing, with the compiler doing all the heavy-lifting of storing away intermediate state for you.

C# BackgroundWorker

I have a button that on click event I get some information from the network.
When I get information I parse it and add items to ListBox. All is fine, but when I do a fast double-click on button, it seems that two background workers are running and after finishing all work, items in the list are dublicated.
I want to do so that if you click button and the proccess of getting information is in work, this thread is stopping and only after first work is completed the second one is beginning.
Yes, I know about AutoResetEvent, but when I used it it helped me only one time and never more. I can't implement this situation and hope that you will help me!
Now I even try to make easier but no success :( : I added a flag field(RefreshDialogs)(default false), when the user clicks on button, if flag is true(it means that work is doing), nothing is doing, but when flag field is set to false, all is fine and we start a new proccess.
When Backgroundwork completes, I change field flag to false(it means that user can run a new proccess).
private void Message_Refresh_Click(object sender, EventArgs e)
{
if (!RefreshDialogs)
{
RefreshDialogs = true;
if (threadBackgroundDialogs.WorkerSupportsCancellation)
{
threadBackgroundDialogs.CancelAsync();
}
if (!threadBackgroundDialogs.IsBusy)
{
downloadedDialogs = 0;
threadBackgroundDialogs = new BackgroundWorker();
threadBackgroundDialogs.WorkerSupportsCancellation = true;
threadBackgroundDialogs.DoWork += LoadDialogs;
threadBackgroundDialogs.RunWorkerCompleted += ProcessCompleted;
threadBackgroundDialogs.RunWorkerAsync();
}
}
}
void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
{
RefreshDialogs = false;
}
So you want to keep the second process running while the first works, but they shouldn't disturb each other? And after the first one finishes the second one continues?
Crude way: While loop:
if (!RefreshDialogs)
{
RefreshDialogs = true;
this becomes:
while(RefreshDialogs)
{
}
RefreshDialogs = true;
After you set it false the second process wwill jump out of the while. (Note this is extremly inefficent since both processes will be running all the time, i'm pretty sure the second one will block the first one, but with multitasking now it shouldn't, if it block use a Dispatcher.Thread)
Elegant way: Use A Semaphore
http://msdn.microsoft.com/de-de/library/system.threading.semaphore%28v=vs.80%29.aspx
If you find it impossible to have both processes running at the same time, or want another way:
Add an Array/List/int and when the second process notices there is the first process running, like with your bool, increase your Added variable, and at the end of the process, restart the new process and decrese the variable:
int number;
if (!RefreshDialogs)
{
RefreshDialogs = true;
your code;
if(number > 0)
{
number--;
restart process
}
}
else
{
number++;
}
I have to admit, i like my last proposal the most, since its highly efficent.
Make your thread blocking. That is easy;
lock(someSharedGlobalObject)
{
Do Work, Exit early if cancelled
}
This way other threads will wait until the first thread releases the lock. They will never execute simultaneously and silently wait until they can continue.
As for other options; why not disable the button when clicked and re-enable it when the backgroundworker completes. Only problem is this does not allow for cancelling the current thread. The user has to wait for it to finish. It does make any concurrency go away very easily.
How about this approach?
Create a request queue or counter which will be incremented on every button click. Every time that count is > 0. Start the background worker. When the information comes, decrement the count and check for 0. If its still > 0 restart the worker. In that your request handler becomes sequential.
In this approach you may face the problem of continuous reference of the count by two threads, for that you may use a lock unlock condition.
I hav followed this approach for my app and it works well, hope it does the same for you.
I'm not an Windows Phone expert, but as I see it has support for TPL, so following code would read nicely:
private object syncRoot =new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
latestTask = Task.Factory.StartNew(action);
else
latestTask = latestTask.ContinueWith(tsk => action());
}
}
Use can use semaphores
class TheClass
{
static SemaphoreSlim _sem = new SemaphoreSlim (3);
static void Main()
{
for (int i = 1; i <= 5; i++)
new Thread (Enter).Start (i);
}
static void Enter (object name)
{
Console.WriteLine (name + " wants to enter");
_sem.Wait();
Console.WriteLine (name + " has entered!");
Thread.Sleep (1000 * (int) name );
Console.WriteLine (name + " is leaving");
_sem.Release(); }
}
}
I found the solution and thanks to #Giedrius. Flag RefreshingDialogs is set to true only when proccess is at the end, when I added items to Listbox. The reason why I'am using this flag is that state of process changes to complete when the asynchronous operation of getting content from network(HttpWebRequest, method BeginGetRequestStream) begins, but after network operaion is complete I need to make UI operations and not only them(parse content and add it to Listbox)My solution is:
private object syncRoot = new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
{
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
else if(latestTask.IsCompleted && !RefreshingDialogs)
{
RefreshingDialogs = true;
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
}
}
private void Message_Refresh_Click(object sender, EventArgs e)
{
Action ac = new Action(LoadDialogs2);
EnqueueAction(ac);
}

Pause and Resume a Thread

I have this code to pause and resume a thread:
public partial class frmMain : Form
{
(...)
ManualResetEvent wait_handle = new ManualResetEvent(true);
(...)
}
private void frmMain_Shown(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(TheLoop));
}
private void TheLoop(object stateinfo)
{
bool hasInfo = true;
while (doLoop)
{
wait_handle.WaitOne();
bool hasLines = GetInfo();
if (hasLines)
{
//Consuming time Operation 1
System.Threading.Thread.Sleep(7000);
if (CurrentLine < line.Count - 1)
CurrentLine++;
else
{
bool hasInfo2 = GetInfo2();
if (hasInfo2)
{
//Consuming time Operation 2
System.Threading.Thread.Sleep(7000);
}
CurrentLine = 0;
}
}
else
System.Threading.Thread.Sleep(40000); //Wait to query again
}
}
private void btnPauseResume_Click(object sender, EventArgs e)
{
if (btnPauseResume.Text == "Pause")
{
btnPauseResume.Text = "Resume";
wait_handle.Reset();
}
else
{
btnPauseResume.Text = "Pause";
wait_handle.Set();
}
}
The code above shows a cycle information, it works find to pause and resume the "first consuming time operation" but doesn't work for the second one, if I press the button to pause the thread in the second consuming time operation, this one continues and when the first one appears again, then it pauses there.
What am I missing here?
Thx
Have you considered using a Background Worker instead since you are using WinForms? It would probably be easier than trying to 'Pause' a thread. You can check the CancellationPending property to see if a user has elected to cancel the operation. The link has a good sample to look at.
I have never seen someone pausing a thread. Create a delegate and event inside the class or method that you are executing on a separate threat. Execute that event whenever you wish to pause your thred.
There is not any reason that I can see that would prevent a second call to WaitOne from working if placed before the 2nd time consuming operation. Since you are using a ManualResetEvent the wait handle's state will persist until either Set or Reset is called. That means if you resume the thread by calling Set then both calls to WaitOne will pass through. Likewise, if you pause the thread by calling Reset then both calls to WaitOne will block. Of course, it will not be possible to predict where the worker thread will pause if there is more than one call to WaitOne.
Got it guys! the thing is where you put the WaitOne(). For instance, if I have a While Loop (like my example) if I put the wait before it, no matter how many times I hit the pause button, it won't stop the thread, it's logic since the loop already began, but if I put it at the end, then it will work.
Appreciated your help.

Categories