Before asking, I'll first show some code...
public partial class Player : UserControl
{
ManualResetEvent _pauseEvent;
ManualResetEvent _stopEvent;
Thread t;
public Player()
{
InitializeComponent();
this.Disposed += (s, a) =>
{
Quit();
};
_pauseEvent = new ManualResetEvent(true);
_stopEvent = new ManualResetEvent(false);
// Creates the thread...
t = new Thread(StartText);
t.IsBackground = false;
// Starts with thread paused...
StopPlaying();
// Let's go!
t.Start();
}
public void StopPlaying()
{
Console.WriteLine("Ordered to stop");
_pauseEvent.Reset();
}
private void ResumePlaying()
{
Console.WriteLine("Ordered to resume");
_pauseEvent.Set();
}
public void Quit()
{
_pauseEvent.Set();
_stopEvent.Set();
}
public void SetText(string text, bool loop)
{
StopPlaying();
// Here we supose the thread would be stopped!!!! But it's not!!!
// But when I call StopPlaying() from a button on the form that
// contains this usercontrol, everything works as expected
...... Do some processing here .....
ResumePlaying();
}
private void StartText()
{
while (true)
{
_pauseEvent.WaitOne(Timeout.Infinite);
if (_stopEvent.WaitOne(0))
break;
do // While LOOP
{
... Do some process here .....
// Verifies if stop requested
if (!_pauseEvent.WaitOne(0))
{
Console.WriteLine("STOP REQUESTED");
break;
}
}
} while (LOOP);
}
}
}
My problem is:
When I call StopPlaying() from a button of the form that contains this UserControl, the test made inside the thread detects correctly, but when I call StopPlaying from the SetText() method it doesn't work, as if the event is not resetted.
By the way, the method SetText() is called by another button of the same form.
It looks like you have a race condition in your StartText() method. You have StartText running on a separate thread and SetText() is called from the main UI thread, so what's probably happening is that SetText() is resetting and then setting _pauseEvent before control is passed back to the other thread. So as far as StartText is concerned the reset never happens.
Related
I am new to C# and I need to show a busy loader when performing heavy task in C# windows form. This is what have tried so far and its showing this error
{"Cross-thread operation not valid: Control 'dataGridView1' accessed from a thread other than the thread it was created on."}
This is my code
//window form
AjaxLoader loader;
//this form is getting called by menu button so its supposed to load the table
public Form1()
{
InitializeComponent();
loader = new AjaxLoader();
in_it();
}
void in_it()
{
ThreadStart threadStart = new ThreadStart(Execution);
Thread thread = new Thread(threadStart);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
private void Execution()
{
dataGridView1.Invoke((MethodInvoker)delegate { loader.Show(); });
Application.DoEvents();
loadData();
dataGridView1.Invoke((MethodInvoker)delegate { loader.Dispose(); });
}
public void loadData()
{
dataGridView1.GridColor = Color.FromArgb(240, 240, 240);
IList<EmployeeEntity> emp = HibenateDao.getRecords<EmployeeEntity>("from EmployeeEntity u");
dataGridView1.DataSource = emp; //error is occuring here
}
You need to Invoke the line loadData(); in your Execution method to make sure that the background UI thread is the only thread reaching the code in loadData where you are making changes to the UI. To invoke it create a delegate in your class
private delegate void UpdateUI();
then use it to invoke
private void Execution()
{
if(InvokeRequired)
{
Invoke(new UpdateUI(Execution));
return;
}
//Now only the UI-thread reaches this code
dataGridView1.Invoke((MethodInvoker)delegate { loader.Show(); });
Application.DoEvents();
loadData();
dataGridView1.Invoke((MethodInvoker)delegate { loader.Dispose(); });
}
Now you should also be able to rewrite your method as
private void Execution()
{
if(InvokeRequired)
{
Invoke(new UpdateUI(Execution));
return;
}
loader.Show();
Application.DoEvents();
loadData();
loader.Dispose();
}
I have form with button and text box. Button is starting thread which is updating value of text box.
public Form1()
{
InitializeComponent();
myDelegate = new UpdateUi(updateUi);
}
private void button1_Click(object sender, EventArgs e)
{
myThread = new Thread(new ThreadStart(ThreadFunction));
myThread.Start();
}
private void ThreadFunction()
{
MyThreadClass myThreadClassObject = new MyThreadClass(this);
myThreadClassObject.Run();
}
private void updateUi(int i)
{
textBox1.Text = i.ToString();
Thread.Sleep(1000);
}
public Thread myThread;
public delegate void UpdateUi(int i);
public UpdateUi myDelegate;
and ThreadClass:
public class MyThreadClass
{
Form1 myFormControl1;
public MyThreadClass(Form1 myForm)
{
myFormControl1 = myForm;
}
public void Run()
{
// Execute the specified delegate on the thread that owns
// 'myFormControl1' control's underlying window handle.
for(int i=0;i<100;i++)
{
if(myFormControl1.InvokeRequired)
{
myFormControl1.Invoke(myFormControl1.myDelegate,i);
}
}
}
}
As You can see there is nothing special in my code but sometimes the code freeze.
eg it goes 1->2->3->freeze->16->17 and so on.
I took code from HERE with little modifications
The issue is you are delaying the UI thread not the the process itself so what happens is you issue all the update commands but since it all runs on the same thread it gets clogged because the Thread.Sleep stops the UI thread so it runs a bunch of textBox1.Text = i.ToString(); then it stops for all the time of all the Thread.Sleep(1000); probably the number of 1->2->3... you see is equal to the number of cores in your machine.
When you stop the run method what happens is you issue one update command that runs immediately and wait for one second until you issue the next command witch I think its what you are trying to accomplish.
I made a thread at load event like below:
Thread checkAlert = null;
bool isStop = false;
private void frmMain_Load(object sender, EventArgs e)
{
checkAlert = new Thread(CheckAlert);
checkAlert.Start();
}
void CheckAlert()
{
while (!isStop)
{
Thread.Sleep(60000);
//do work here
}
}
Is there any way to resume the checkAlert thread during it's sleep period?( Thread.Sleep(60000);)
I tried using Thread.Interrupt() but it flows a ThreadInterruptedException, how should I handle this exception? or is there any way to resume the thread?
Edited:
I need to wake up the thread before the "sleep" end because when the user wants to quit the program, the program will have to wait for some time before it really quits ( checkAlert is still running) Is there any way to improve this case?
Based on your comments what it looks like is you need to re-design how CheckAlert works so it does not use Sleep's at all. What you should be doing is using a Timer instead.
System.Timers.Timer timer = null;
public FrmMain()
{
InitializeComponent();
timer = new System.Timers.Timer(60000);
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
//If you want OnTimedEvent to happen on the UI thread instead of a ThreadPool thread, uncomment the following line.
//timer.SynchronizingObject = this;
if(this.components == null)
this.components = new System.ComponentModel.Container();
//This makes it so when the form is disposed the timer will be disposed with it.
this.componets.Add(timer);
}
private void frmMain_Load(object sender, EventArgs e)
{
timer.Start();
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
//It is good practice not to do complicated logic in a event handler
// if we move the logic to its own method it is much easier to test (you are writing unit tests, right? ;) )
CheckAlert();
}
void CheckAlert()
{
//do work here
}
private void frmMain_Close(object sender, EventArgs e)
{
timer.Stop();
}
If you want the thread to exit automatically when your program quits, simply make it a background thread.
checkAlert = new Thread(CheckAlert);
checkAlert.IsBackground = true;
checkAlert.Start();
It looks to me like you're trying to create a thread which handles two types of events: do something and stop running.
Rather than using a shared variable (isStop) and some other technique to interrupt the thread in order to do work, you might want to use threading events (not to be confused high-level UI Event objects) to control your thread.
AutoResetEvent stop = new AutoResetEvent(false);
AutoResetEvent check = new AutoResetEvent(false);
private void CheckAlert() {
WaitHandle[] handles = new WaitHandle[] { stop, check };
for (;;) {
switch (AutoResetEvent.WaitAny(handles)) {
case 0:
return;
case 1:
// do work
break;
}
}
}
Calling check.Set() in your code will trigger the "do work" branch in the thread and stop.Set() will cause the thread to terminate gracefully.
Once your code has called stop.Set() to terminate the thread, it can call the thread's Join() method to wait until the thread terminates.
EDIT
I misunderstood the question. I will leave the code above in case anyone finds it useful.
If all you want to do is have a thread that performs a task once a minute and stop on demand, you can use the following code:
AutoResetEvent stop = new AutoResetEvent(false);
void CheckAlert() {
var time = new TimeSpan(0, 1, 0); // one minute
while (!stop.WaitOne(time)) {
// do work
}
}
private Thread checkThread;
private void frmMain_Load(object sender, EventArgs e) {
checkThread = new Thread(CheckAlert);
checkThread.Start();
}
private void frmMain_Close(object sender, EventArgs e) {
stop.Set(); // signal thread to stop
checkThread.Join(); // wait for thread to terminate
}
You can see an explanation on how to wake a sleeping thread here:
https://msdn.microsoft.com/en-us/library/tttdef8x%28v=vs.100%29.aspx
and this is a complete example (as you can see, Thread.Interrupt is the good choise... however you have to catch it to continue normal thread execution):
public class HVCSensor : HVCDevice, IDisposable
{
private Thread myThread;
private const int execute_timeout = ((10 + 10 + 6 + 3 + 15 + 15 + 1 + 1 + 15 + 10) * 1000);
private bool disposed = false;
private bool paused = false;
public delegate void HVCResultsHandler(HVC_RESULT res);
public event HVCResultsHandler HVCResultsArrived;
private void OnHVCResultsArrived(HVC_RESULT res)
{
if (HVCResultsArrived != null) {
HVCResultsArrived(res);
}
}
public HVCSensor() {
myThread = new Thread(new ThreadStart(this.execute));
}
private void execute(){
while (!disposed) {
if (!paused && this.IsConnected)
{
HVC_RESULT outRes;
byte status;
try
{
this.ExecuteEx(execute_timeout, activeDetections, imageAcquire, out outRes, out status);
OnHVCResultsArrived(outRes);
}
catch (Exception ex) {
}
}
else {
try
{
Thread.Sleep(1000);
}
catch (ThreadInterruptedException e)
{
}
}
}
}
public HVC_EXECUTION_IMAGE imageAcquire
{
get;
set;
}
public HVC_EXECUTION_FLAG activeDetections
{
get;
set;
}
public void startDetection() {
if(myThread.ThreadState==ThreadState.Unstarted)
myThread.Start();
}
public void pauseDetection() {
paused = true;
}
public void resumeDetection() {
paused = false;
if (myThread.ThreadState == ThreadState.WaitSleepJoin)
myThread.Interrupt();
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
disposed = true;
myThread.Interrupt();
}
}
I am using
System.Threading.ThreadPool.QueueUserWorkItem(x => MyMethod(param1, param2, param3, param4, param5));
I want to call the following method from the main thread every time the call to MyMethod is completed:
UpdateGui()
{
}
How do I do that?
Thanks!
Keep a global counter of work items queued and an object to protect it:
int runningTasks = 0;
object locker = new object();
Every time a task is added increment the counter:
lock(locker) runningTasks++;
System.Threading.ThreadPool.QueueUserWorkItem(x => MyMethod(param1, param2, param3, param4, param5));
At the end of MyMethod decrement the counter and signal the main thread:
lock(locker)
{
runningTasks--;
Monitor.Pulse(locker);
}
In the main thread (assuming this is not the GUI thread!):
lock(locker)
{
while(runningTasks > 0)
{
Monitor.Wait(locker);
UpdateGUI();
}
}
This way you also have a barrier to wait for all pending tasks to finish.
In case you don't want to wait, just skip the main thread completely and call UpdateGUI to forward updates to the GUI thread when MyMethod finishes.
Note that inside MyMethod you should have some form of Dispatcher.BeginInvoke (WPF) or Control.BeginInvoke (WinForms) otherwise you cannot update the GUI safely!
Post a call to the updategui method back to the sync context for the ui thread at the end of the threadpool method...
Example:
private SynchronizationContext _syncContext = null;
public Form1()
{
InitializeComponent();
//get hold of the sync context
_syncContext = SynchronizationContext.Current;
}
private void Form1_Load(object sender, EventArgs e)
{
//queue a call to MyMethod on a threadpool thread
ThreadPool.QueueUserWorkItem(x => MyMethod());
}
private void MyMethod()
{
//do work...
//before exiting, call UpdateGui on the gui thread
_syncContext.Post(
new SendOrPostCallback(
delegate(object state)
{
UpdateGui();
}), null);
}
private void UpdateGui()
{
MessageBox.Show("hello from the GUI thread");
}
Assuming that MyMethod is a synchronous method, invoked inside QueueUserWorkItem in order to make it execute asynchronously, the following approach may be used:
ThreadPool.QueueUserWorkItem(x =>
{
MyMethod(param1, param2, param3, param4, param5);
UpdateGui();
});
Note that you have to update GUI elements inside UpdateGui() by calling Invoke/BeginInvoke.
This may keep the client cleaner letting the class handle the cross threading switching mechanism. This way the GUI consumes your class in normal fashion.
public partial class Form1 : Form
{
private ExampleController.MyController controller;
public Form1()
{
InitializeComponent();
controller = new ExampleController.MyController((ISynchronizeInvoke) this);
controller.Finished += controller_Finished;
}
void controller_Finished(string returnValue)
{
label1.Text = returnValue;
}
private void button1_Click(object sender, EventArgs e)
{
controller.SubmitTask("Do It");
}
}
The GUI form subscribes to events of the class unaware they are mulch-threaded.
public class MyController
{
private ISynchronizeInvoke _syn;
public MyController(ISynchronizeInvoke syn) { _syn = syn; }
public event FinishedTasksHandler Finished;
public void SubmitTask(string someValue)
{
System.Threading.ThreadPool.QueueUserWorkItem(state => submitTask(someValue));
}
private void submitTask(string someValue)
{
someValue = someValue + " " + DateTime.Now.ToString();
System.Threading.Thread.Sleep(5000);
//Finished(someValue); This causes cross threading error if called like this.
if (Finished != null)
{
if (_syn.InvokeRequired)
{
_syn.Invoke(Finished, new object[] { someValue });
}
else
{
Finished(someValue);
}
}
}
}
I have two forms, the main form and one that pops up as a modal dialog. From a process spawned in the main form, I want to dynamically update the text on the modal dialog. Here's what I have:
In the main form, I do this:
// show the wait modal
var modal = new WaitDialog { Owner = this };
// thread the packaging
var thread = new Thread(() => Packager.PackageUpdates(clients, version, modal));
thread.Start();
// hopefully it worked ...
if (modal.ShowDialog() != DialogResult.OK)
{
throw new Exception("Something failed, miserably.");
}
The PackageUpdates method takes the modal dialog, and does this:
// quick update and sleep for a sec ...
modal.SetWaitLabelText("Downloading update package...");
Thread.Sleep(2000);
modal.SetWaitLabelText("Re-packaging update...");
To be thread safe, I do this in the modal dialog:
public void SetWaitLabelText(string text)
{
if (lblWaitMessage.InvokeRequired)
{
Invoke(new Action<string>(SetWaitLabelText), text);
}
else
{
lblWaitMessage.Text = text;
}
}
Everything works great ... most of the time. Every three or four times that the modal pops up, I get an exception on the lblWaitMessage.Text = text; and it's not invoking the command.
Am I missing something in this setup?
Like #Hans Passant pointed out, you should wait for the modal.Load-event. One good option is to use the ManualResetEvent to inform your thread to wait until that happens.
The WaitOne method will block the thread until the Set method is called. Here's a very simple setup which should do the trick.
public partial class Form1 : Form
{
ManualResetEvent m_ResetEvent;
public Form1()
{
InitializeComponent();
m_ResetEvent = new ManualResetEvent(false);
}
private void button1_Click(object sender, EventArgs e)
{
Dialog d = new Dialog { Owner = this, ResetEvent = m_ResetEvent };
var thread = new Thread(new ParameterizedThreadStart(DoSomething));
thread.Start(d);
if (d.ShowDialog() != System.Windows.Forms.DialogResult.OK)
{
throw new Exception("Something terrible happened");
}
}
private void DoSomething(object modal)
{
Dialog d = (Dialog)modal;
// Block the thread!
m_ResetEvent.WaitOne();
for (int i = 0; i < 1000; i++)
{
d.SetWaitLabelText(i.ToString());
Thread.Sleep(1000);
}
}
}
And here is the modal form
public partial class Dialog : Form
{
public Form Owner { get; set; }
public ManualResetEvent ResetEvent { get; set; }
public Dialog()
{
InitializeComponent();
}
public void SetWaitLabelText(string text)
{
if (label1.InvokeRequired)
{
Invoke(new Action<string>(SetWaitLabelText), text);
}
else
{
label1.Text = text;
}
}
private void Dialog_Load(object sender, EventArgs e)
{
// Set the event, thus unblocking the other thread
ResetEvent.Set();
}
}
I think you should rewrite the code to let thread.Start() isn't called before modal.ShowDialog().
As a workaround, you can try this:
public void SetWaitLabelText(string text) {
Invoke(new Action<string>(SetWaitLabelText2), text);
}
void SetWaitLabelText2(string text) {
lblWaitMessage.Text = text;
}
The first method always uses Invoke, regardless the value of InvokeRequired. The second method actually does the thing. This pattern is usable when you always call the function from another thread.