I use Semaphore In this code
static Semaphore s = new Semaphore(1,1);
private void button2_Click(object sender, EventArgs e)
{
Thread[] t = new Thread[full_list];
for(int i=0;i<full_list;i++)
{
if (sorted_list[i].audio_node != null)
if (sorted_list[i].audio_node.Checked == true)
{
t[i] = new Thread(DownloadFile);
t[i].Start(sorted_list[i]);
}
}
}
private void DownloadFile(object a)
{
s.WaitOne();
if (InvokeRequired)
{
BeginInvoke(new DownloadFileDelegate(DownloadFile),new object[1] {a} );
return;
}
else
{
download process....
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
s.Release();
}
But it doesn't work, my prorgram freezes. I am trying solve this problem, but i don't know why it doesn't work with Semaphore. All components include downloading work correctly.
You're running DownloadFile on a non-gui thread. In the method you acquire the semaphore, and then call InvokeRequired. It will return true as you're not on the gui thread, so you're invoke DownloadFile on the gui thread. You then return without releasing the semaphore, so whenDownloadFile` runs on the gui thread the first thing it will try to do is acquire the semaphore, and because it can't it will block.
There's not much point in creating a thread in your code that is just going to schedule a call back on the gui thread. What you really need to do is download the file on the non-gui thread, and then when you've got it make a call back onto the gui thread to handle what you've downloaded.
Regarding the semaphore, you should wrap the code in a try\finally block to make sure it's always released, even if you've got a return in the middle of the code:
s.WaitOne();
try
{
// Rest of method
}
finally
{
s.Release();
}
Related
I have a thread running, which grabs images from a camera, saves them, and updates the pictureBox to display that bitmap. When I want to exit the application, I set my bool exitApplication to true, but it never returns on the join() call.
public void GrabThread()
{
Bitmap copyBmp;
while (!exitApplication)
{
mImage = m_camera.GrabImage();
SaveImage();
copyBmp = (Bitmap)mImage.bmp.Clone();
if (pictureBox1.InvokeRequired)
{
pictureBox1.Invoke(new MethodInvoker(
delegate ()
{
pictureBox1.Image = copyBmp;
}));
}
else
{
pictureBox1.Image = copyBmp;
}
m_camera.ReleaseImage();
}
}
My Exit code:
exitApplication = true;
threadGrab.Join();
m_camera.Stop();
Close();
When I call Break All from the Debug menu, the Thread hangs at
pictureBox1.Invoke(new MethodInvoker(
delegate ()
{
pictureBox1.Image = copyBmp;
}));
Why? And how can I prevent this? Currently I have to call Abort() on the thread to exit it.
This code deadlocks because pictureBox1.Invoke is trying to execute code in the UI thread. That thread though is blocked by the call to threadGrab.Join();
This can be fixed using async/await. await awaits already executing asynchronous tasks without blocking the way Join() does. When it finishes, execution resumes in the original synchronization context. In a WinForms or WPF application, this means execution resumes on the UI thread.
I assume the only thing that needs to run in the background is m_camera.GrabImage();. In that case, the code could look something like this :
public async void Button1_Click(object sender, EventArgs args)
{
await Task.Run(()=>m_camera.GrabImage();
//Back in the UI thread
SaveImage();
var copyBmp = (Bitmap)mImage.bmp.Clone();
pictureBox1.Image = copyBmp;
m_camera.ReleaseImage();
}
Task.Run will execute m_camera.GrabImage() in a threadpool thread. await will await for this to finish without blocking the UI thread. When it finishes, execution resumes in the UI thread which means there's no need for Invoke.
This could run in a loop too :
public async void Capture_Click(object sender, EventArgs args)
{
while(someCondition)
{
await Task.Run(()=>m_camera.GrabImage();
SaveImage();
var copyBmp = (Bitmap)mImage.bmp.Clone();
pictureBox1.Image = copyBmp;
m_camera.ReleaseImage();
}
}
It may not the right answer but you can using both OnClosing and OnClosed to Stop your camera then close your app, I don't know does it work in Winform but it worked with me in WPF
protected override void OnClosing(CancelEventArgs e)
{
e.Cancel = false; //prevent your application to shutdown
Camera.Stop(); //stop your camera
base.OnClosing(e);
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
Application.Current.Shutdown(); //then shutdown again
}
Via 2 step, your camera will stop without Join any thread. And note that this code is written in Wpf, not Winform but I thought you can find a similar way to do in Winform
Hope this answer may help you.
I have the following code. It is just a form app. On load it will run the bacground worker.
Then I have a button that is supposed to stop the infinite loop in the background worker by setting a flag to true.
I'm logging the out put of the backgroundworker1.IsBusy and it says it is busy but according to the logic in my code it shouldn't be busy because I set the flag to true thus exiting the while loop and running the backgroundworker_Completed event.
I must be doing something wrong but I can not figure it out.
If I'm approaching this incorrectly could somebody either help me fix what I'm doing wrong or point me in a better direction on how I can accomplish what I"m trying to do here.
private volatile bool StopScanning = false;
private void myForm_Load(object sender, EventArgs e)
{
try
{
if (backgroundWorker1.IsBusy)
{
//do nothing
}
else
{
backgroundWorker1.RunWorkerAsync();
}
}
catch (Exception boo)
{
Log.log(boo.ToString());
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (StopScanning == false)
{
Application.DoEvents();
try
{
ReturnScannedItems();
System.Threading.Thread.Sleep(1000);
}
catch (Exception boo)
{
Log.log(boo.ToString());
}
}
}
private void cancelbutton_Click(object sender, EventArgs e)
{
try
{
Log.log("Setting Stop Scan flag to true");
StopScanning = true;
Log.log(CloseScanSession().ToString());
}
catch (Exception boo)
{
Log.log("Setting Stop Scan flag to true");
StopScanning = true;
Log.log(CloseScanSession().ToString());
Log.log(boo.ToString());
}
while (backgroundWorker1.IsBusy)
{
Log.log("Still busy");
}
this.Close();
}
You are blocking the UI thread, which prevents the BackgroundWorker from completing. It can't raise the RunWorkerCompleted event until the UI thread is free to process new messages (raising the event involves posting a message to the UI thread's message queue, so that the UI thread can then execute the code that will actually raise the event).
Your code also is flawed in that it's calling Application.DoEvents() from the worker thread. You should never call this method anyway, but it's particularly foolish to call it from a worker thread, because the whole point of having a worker thread is to avoid having to call that method (and it won't do anything when called on the worker thread anyway, because the worker thread shouldn't own any window objects that would need to receive a window message).
Instead of sitting in a busy loop, checking IsBusy and blocking the UI thread, you should just subscribe to the RunWorkerCompleted event and do whatever you need to do there. Without a good Minimal, Complete, and Verifiable code example that fully illustrates what you're actually trying to do, it's not possible to provide any more specific advice than that.
I have a class that updates a progress bar on my GUI.
I used the backgroundWorker, both with the 'DoWork' and the 'RunWorkerCompleted' but both gave me the same error:
"accessed from a thread other than the thread it was created on"
I thought that by using the method "RunWorkerAsync()" it runs the commands on the GUI thread, so I guess I was wrong.
Here is the relevant code (tried both DoWork and RunWorkerCompleted):
this.backgroundWorker2.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker2_RunWorkerCompleted);
private void backgroundWorker2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
try
{
this.progressBar1.PerformStep();
}
catch (Exception Ex)
{
Program.handleException(Ex, MethodBase.GetCurrentMethod().Name);
}
}
//public access from another class, that's my main problem
//I don't activate the performStep() by pressing a button but its called by progress...
//BTW, the while loop isn't efficient it is temporary..
public void performStep()
{
try
{
this.backgroundWorker2.RunWorkerAsync();
while (this.backgroundWorker2.IsBusy)
{
Console.WriteLine("worker2 is busy");
}
}
catch (Exception Ex)
{
Program.handleException(Ex, MethodBase.GetCurrentMethod().Name);
}
}
Does anyone know why it still gives that error? (btw I tried to use delegates but found this way more convenient and recommended by MSDN so I would like to stick to this method..)
Thanks a lot!!
Backgroundworker does not run the commands on the GUI thread. It runs them on a separate, dedicated thread.
To run things on the UI thread, you use the Invoke method on your control:
private void PerformStep()
{
if (progressBar1.InvokeRequired)
{
progressBar1.Invoke(
new MethodInvoker(() => progressBar1.PerformStep()));
}
else
{
progressBar1.PerformStep();
}
}
Imagine following situation:
I got a signal on the ui thread from a third party server.
I start a BackgroundWorker with RunAsync to fetch data from a database and another async thread, which shall poll
another hardware and receive signals, also not in ui thread
Inside the bg's DoWork eventhandler I call manualresetEvent.Reset(). Then I call the data-fetching method, and then I call manualresetEvent.Set() and in the end I call the method METH_UI_1 on the ui thread by invoking it.
The other hardware thread shall receive hardware-data, which then itself is passed via Invoke to the ui into the ui thread to set some ui-elements periodically depending on the hardware-data I get.
The data from database can also not be fetched yet, but the ui must react to the hardware-data, which is polled by the second async thread.
In METH_UI_1 I call manualresetEvent.WaitOne();
Some times I get the exception, that the background worker is busy and cannot run multiple tasks concurrently.
a) Is there really a need for a ManualResetEvent object ?
b) Would it be enough, to check for the isBusy property in order to issue WaitOne() only, when the background worker is no more busy ?
UPDATE: CODE.
MainForm.cs (event handler of third party hw-vendor, component, handled in ui thread)
private void thrdptyPlcGotData(object sender, thrdptyPlcGotDataEventArgs e)
{
string strError = string.Empty;
bool blNotReadyYet = false;
try
{
ThrdPtyPlcIfs.DataSetthrdptyPlc ds;
ds = new ThrdPtyPlcIfs.Dataset();
e.FillDataToTDataSet(ds);
ThrdPtyPlcIfs.Statics.SaveDataSet(ds, CLStatics.FileName);
if (this.ValidateDsDetail(ds))
{
// begin async work..... ask db, continue asking scale-> inside got weight of scale the rest is handled ( using or trashing db data )
this.ExtractDataOfDataSet(ds);
this.bgWorkerStart_Get_Data.RunWorkerAsync();
_oAsyncScaleManager.StartThread();
}
}
}
runworkerasynch does this:
private void bgWorkerStart_Get_Data_RFC_DoWork(object sender, DoWorkEventArgs e)
{
try
{
_blnStart_Get_Data_RFC = this.StartGetData_RFC(null);
}
catch (Exception ex)
{
LogExcep(ex);
_blnStart_Get_Data_RFC = false;
}
}
WorkCompleted EventHandler of the BackGroundWorker:
private void bgWorkerStart_Get_Data_RFC_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
try
{
if (InvokeRequired)
{
this.Invoke((MethodInvoker)delegate()
{
this.ApplyDbDataToUi();
}
);
}
else
{
this.ApplyDbDataToUi();
}
}
catch (Exception ex)
{
LogAndShowExep(ex);
}
}
As rare as it might be , its possible the BackgrounWorker isn't finished when you set manualresetEvent inside the dowork method block. If its at the very end , I would hook into the backgroundworker workcompleted event and set it in there.
I have a Thread that starts in my main form
private void changePasswordbutton_Click_1(object sender, EventArgs e)
{
waitForm.Show();
Thread thread = new Thread(ProcessInkPresenter);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
waitForm.Hide();
waitForm.Dispose();
}
I want to close the waitForm inside the ProcessInkPresenter method (which is running on a thread) instead of waiting for the thread to complete.
How do I do this?
Thanks
Method signatures
private void ProcessInkPresenter()
Defined in the class header
Wait waitForm;
Your original code doesn't make sense. It shows a form, then starts a thread, then waits for that thread to complete. If you want the form to be run on it's own UI thread, have ProcessInkPresenter run on the same UI thread (which it should if it interacts with the UI) and have the form closed and be disposed of when ProcessInkPresenter completes, try this:
private void changePasswordbutton_Click_1(object sender, EventArgs e)
{
Thread thread = new Thread(state => {
using (var waitForm = new WaitForm()) {
waitForm.Activated += (s, e) => {
ProcessInkPresenter();
waitForm.Hide();
}
Application.Run(waitForm);
}
}
);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
If the worker thread does not have to interact with the GUI, then what you want is something like the following. Note that I make use of Invoke to make sure that the interaction with the UI is done on the UI thread. There is no need to check InvokeRequired here, since I already know for sure that I am on a background thread.
If you want to keep the same waitForm instance:
private void changePasswordbutton_Click_1(object sender, EventArgs e)
{
Thread thread = new Thread(state => {
try {
ProcessInkPresenter();
// If ProcessInkPresenter fails, this line will never execute
waitForm.Invoke(new Action(()=>waitForm.Hide()));
}
catch (Exception ex) {
// You probably want to do something with ex here,
// rather than just swallowing it.
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
waitForm.Show();
}
NOTE: It doesn't make sense to dispose your WaitForm if you have a single instance of it (your Wait instance). Either construct an instance each time you use it, or never dispose it and use .Hide() instead.