I want when i click thread.Abort() and thread finish print label after that it will abort. It only abort thread when finish current job. Thanks
namespace ThreadTest
{
public partial class Form1 : Form
{
Thread thread;
bool loop = true;
Stopwatch regularSW = new Stopwatch();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
thread = new Thread(new ThreadStart(() => threadtest()));
thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
thread.Abort();
}
public void threadtest()
{
while (loop)
{
regularSW.Start();
Thread.Sleep(5000);
regularSW.Stop();
this.Invoke(new Action(() => label1.Text += "Sleep in: " + regularSW.Elapsed + Environment.NewLine));
}
}
}
}
Thread.Abort is a request, the operating system and thread are free to ignore it in situations where an abort is not possible. Generally, Abort should never be used in "by design" scenarios. Instead, your loop should check to see if there is a cancel action pending, perhaps something like this:
Thread thread;
bool loop = true;
volatile bool _cancelPending = false;
Stopwatch regularSW = new Stopwatch();
//Snip... unchanged code removed for brevity.
private void button2_Click(object sender, EventArgs e)
{
_cancelPending = true;
}
public void threadtest()
{
while (loop)
{
if (_cancelPending) break;
regularSW.Start();
Thread.Sleep(5000);
regularSW.Stop();
this.Invoke(new Action(() => label1.Text += "Sleep in: " + regularSW.Elapsed + Environment.NewLine));
}
}
Perhaps that is the purpose of your loop field, but I introduced another field, _cancelPending, in-case it is serving a different purpose.
Aborting a thread is not something you should need to do in most applications; when the thread no longer has work to do, it will stop as a natural part of its lifecycle.
To allow this to happen, your code needs to signal that the method should stop executing. In .NET, the type CancellationTokenSource is used to allow thread-safe signalling that an operation should be stopped.
However, the most prominent concern is that your thread spends most of its time sleeping. This means that when the Cancel button is pressed, you must wait for the thread to wake up before it will notice that cancellation has been requested.
We can use the cancellation mechanism to simulate the thread sleeping by having it wait for a period of time, or for cancellation to be requested - whichever happens first:
Thread thread;
CancellationTokenSource cts;
Stopwatch regularSW = new Stopwatch();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
thread = new Thread(new ThreadStart(() => threadtest(cts.Token)));
thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
cts.Cancel();
}
public void threadtest(CancellationToken cancellation)
{
while (!cancellation.IsCancellationRequested)
{
regularSW.Start();
// Simulate a Thread.Sleep; returns true if cancellation requested.
if (!cancellation.WaitHandle.WaitOne(5000))
{
regularSW.Stop();
this.Invoke(() => label1.Text += "Sleep in: "
+ regularSW.Elapsed
+ Environment.NewLine);
}
}
}
Related
The WinForm application has 20 threads running in the background, each one waits on the mutex. When signaled, it does "a job" as in Thread.Sleep for around 100ms and releases it. Then waits 1 second, and does the job again.
private Mutex locker;
private void NewThread()
{
Thread thread = new Thread(ThreadLoopMutex);
thread.Priority = ThreadPriority.BelowNormal;
thread.Name = threadCounter++.ToString("D2");
thread.Start();
}
private void ThreadLoopMutex()
{
PrintLog("was created");
while (true)
{
PrintLog("Lock1");
locker.WaitOne();
Thread.Sleep(100);
PrintLog("UnLock1");
locker.ReleaseMutex();
Thread.Sleep(1000);
PrintLog("Lock2");
locker.WaitOne();
Thread.Sleep(100);
PrintLog("UnLock2");
locker.ReleaseMutex();
}
}
public Form1()
{
InitializeComponent();
locker = new Mutex();
Thread.CurrentThread.Name = "GUI";
Thread.CurrentThread.Priority = ThreadPriority.Highest;
for (int i = 0; i < 20; i++)
{
NewThread();
}
}
When the GUI Thread tries to wait on the same mutex, it never signals. It will wait on the Mutex for a long time while the other threads are playing with it smoothly.
When I set the 20 threads' job time to 30ms instead of 100ms, then the GUI Thread enters the mutex freely.
private void button1_Click(object sender, EventArgs e)
{
PrintLog("Lock");
locker.WaitOne();
Thread.Sleep(500);
PrintLog("UnLock");
locker.ReleaseMutex();
}
Why is that?
This question already has answers here:
c# Thread issue using Invoke from a background thread
(5 answers)
Closed 6 years ago.
I can't seem to be able to kill my thread in C#. The program seems to get stuck in an infinite loop on the FormClosing event.
EDIT // I'm attempting to end the thread and close the whole program when the FormClosing event gets fired.
Here's the code:
public partial class Form1 : Form
{
private Thread thread;
private volatile bool threadRunning = true;
public Form1()
{
InitializeComponent();
}
private void Loop()
{
Console.WriteLine(threadRunning);
while (threadRunning)
{
MethodInvoker mi = delegate { timeLabel.Text = TimeWriterSingleton.Instance.OutputTime(); };
Invoke(mi);
}
}
private void Form1_Load(object sender, EventArgs e)
{
thread = new Thread(Loop);
thread.Start();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
threadRunning = false;
thread.Join();
}
}
Your Join blocked the GUI thread, and your Invoke in the other thread is waiting for your GUI thread to process the delegate.
A quick fix would be to use BeginInvoke instead of Invoke, thus posting rather than sending the window message.
Alternatively, don't join. The purpose of that code is to clean up after yourself, why do you care when the thread dies?
A 3rd fix would be to just gut the thread, either through Thread.Abort or Environment.Exit. It might skip some clean up, but your particular code shouldn't care and the point is to exit anyway.
Edit: working code using BeginInvoke follows:
private void Loop()
{
while (threadRunning)
{
BeginInvoke(new MethodInvoker(() => timeLabel.Text = DateTime.Now.ToString()));
Thread.Sleep(100);
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
threadRunning = false;
thread.Join();
}
The issue with the original code is that it's running as fast as your CPU allows, filling the message queue to the point where the GUI thread can't keep up. Updating Windows controls is very expensive, compared to simply adding a number to a queue. So I added a pause between UI updates to let the GUI thread breathe.
To the downvoters, I'd be curious why you're doing it. Nothing I said is factually wrong.
I decided to switch to using a timer. The code now looks like this, and the application works:
public partial class Form1 : Form
{
private System.Timers.Timer timer;
public Form1()
{
InitializeComponent();
timer = new System.Timers.Timer(60000);
}
private void Form1_Load(object sender, EventArgs e)
{
timeLabel.Text = TimeWriterSingleton.Instance.OutputTime();
timer.Elapsed += TimerElapsed;
timer.Enabled = true;
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
timeLabel.Text = TimeWriterSingleton.Instance.OutputTime();
}
}
Actually using the BeginInvoke() is not bad idea. It might look like that:
private void Form1_Load(object sender, EventArgs e)
{
thread = new Thread(() => Loop(this));
thread.Start();
}
private void Loop(Form1 form)
{
while (threadRunning && !form.IsDisposed)
{
MethodInvoker mi = delegate() { timeLabel.Text = /* Some text */ ; };
BeginInvoke(mi);
// Let sleep some time...
Thread.Sleep(1);
}
}
private void Form1_FormClosing_1(object sender, FormClosingEventArgs e)
{
threadRunning = false;
thread.Join();
}
This is code freezing current window. How to made non freezing this form.
public partial class Form1 : Form
{
Thread t;
int s = 0;
public Form1()
{
InitializeComponent();
label2.Text = "Push the Button";
button1.Text = "Push me!";
button1.Click += new EventHandler(button1_Click);
this.Controls.Add(label2);
this.Controls.Add(button1);
}
void button1_Click(object sender, EventArgs e)
{
t = new Thread(new ThreadStart(RunMe));
t.Start();
}
private void RunMe()
{
if (!InvokeRequired)
{
while(true)
{
label2.Text = s.ToString();
s++;
Task.Delay(10000).Wait(10000);
}
}
else
{
Invoke(new ThreadStart(RunMe));
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
As others have stated, you are using the UI thread to execute an endless loop, you should use the Timer control, it was built for exactly what you're doing.
https://social.msdn.microsoft.com/Forums/windows/en-US/43daf8b2-67ad-4938-98f7-cae3eaa5e63f/how-to-use-timer-control-in-c?forum=winforms
Your code can benefit from using async-await if you are using .net 4.5. Using await you won't have to start a seperate thread for your RunMe method, it will free up your UI thread to do other work but the SynchronizationContext is captured so that you don't have to use Invoke to update the UI. For how that works, see this blog.
I think you should be able to rewrite your code like this:
async void button1_Click(object sender, EventArgs e)
{
// kicks off the RunMe method and returns
await RunMe();
}
private Task RunMe()
{
while(true)
{
label2.Text = s.ToString();
s++;
await Task.Delay(10000);
}
}
Despite the infinite while loop the method only wakes up to update the label and runs for a very short time in the UI thread.
You should call the invoke only for updating the label like this:
while(true)
{
if (!InvokeRequired)
{
label2.Text = s.ToString();
}
else
{
Invoke(new Action(()=>{label2.Text = s.ToString();}));
}
s++;
Task.Delay(10000).Wait(10000);
}
I want to modify interval value of timer which is instance of System.Microsoft.Timer from a worker thread
When i change this value in the thread running worker thread, Timer is stopped.
let see my source code
private void Scan_Screen(object sender, EventArgs e)
{
textBox1.Text += "a";
}
private void button1_Click(object sender, EventArgs e)
{
g_RECEIVER_timer = new System.Windows.Forms.Timer();
g_RECEIVER_timer.Enabled = true;
g_RECEIVER_timer.Interval = TIMER_INTERVAL;
g_RECEIVER_timer.Tick += new EventHandler(Scan_Screen);
}
private void button2_Click(object sender, EventArgs e)
{
g_Control_Thread = new Thread(new ParameterizedThreadStart(Control_Message_Receiver));
g_Control_Thread.Start(200);
}
//thread function
public void Control_Message_Receiver(object v)
{
g_RECEIVER_timer.Stop();
g_RECEIVER_timer.Interval = 200;
g_RECEIVER_timer.Enabled = true;
g_RECEIVER_timer.Tick += new EventHandler(Scan_Screen);
}
Why this happening is occurred? Also how can i make this run? (I want to adjust interval value of timer in the worker thread)
You need to invoke this Control_Message_Receiver on the UI thread since you have spawned another worker thread and you are accessing objects on the UI thread context.
And don't need to re-declare the Tick event on your worker thread method.
Look at this snippet below:
private void Scan_Screen(object sender, EventArgs e)
{
textBox1.Text += "a";
}
private void button1_Click(object sender, EventArgs e)
{
g_RECEIVER_timer = new System.Windows.Forms.Timer();
g_RECEIVER_timer.Enabled = true;
g_RECEIVER_timer.Interval = 1000;
g_RECEIVER_timer.Tick += new EventHandler(Scan_Screen);
}
private void button2_Click(object sender, EventArgs e)
{
Thread g_Control_Thread = new Thread(new ParameterizedThreadStart(Control_Message_Receiver));
g_Control_Thread.Start(1);
}
//thread function
public void Control_Message_Receiver(object v)
{
//timer1.Stop(); //why stop? -- remove this instead
IntervalChange((int)v); //call this method and invoke it on the UI thread
g_RECEIVER_timer.Enabled = true;
//timer1.Tick += new EventHandler(Scan_Screen); // -- remove this
}
delegate void intervalChanger(int time);
void ChangeInterval(int time)
{
g_RECEIVER_timer.Interval = time;
}
void IntervalChange(int time)
{
this.Invoke(new intervalChanger(ChangeInterval), new object[] {time}); //invoke on the UI thread
}
It may be better to use System.Threading.Timer. This one can be readjusted from any thread. Note, however, that the timer callback runs in a threadpool thread. So you have to use Invoke, if you need to access the GUI from this callback.
I'm learning about threads in C#, and i get this behavior that i cant understand.
The code simulates I/O operations, like files or serial port, where only one thread can access it at time, and it blocks until finishes.
Four threads are started. Each performs just a count. It works ok, i can see on the form the counts growing. But there is a button to count from the form thread. When i push it, the main thread freezes. The debugger shows that the others threads keep counting, one by one, but the form thread never gets access to the resource.
1) Why the lock(tty) from the form thread never gets access to it, when the others threads has no problem ?
2) Is there a better way to do this type of synchronization ?
Sorry about the big code:
public class MegaAPI
{
public int SomeStupidBlockingFunction(int c)
{
Thread.Sleep(800);
return ++c;
}
}
class UIThread
{
public delegate void dlComandoMaquina();
public class T0_SyncEvents
{
private EventWaitHandle _EventFechar; // Exit thread event
public T0_SyncEvents()
{
_EventFechar = new ManualResetEvent(false);
}
public EventWaitHandle EventFecharThread // Exit thread event
{
get { return _EventFechar; }
}
}
public class T0_Thread
{
private T0_SyncEvents _syncEvents;
private int _msTimeOut;
private dlComandoMaquina _ComandoMaquina;
public T0_Thread(T0_SyncEvents e, dlComandoMaquina ComandoMaquina, int msTimeOut)
{
_syncEvents = e;
_msTimeOut = msTimeOut;
_ComandoMaquina = ComandoMaquina;
}
public void VaiRodar() // thread running code
{
while (!_syncEvents.EventFecharThread.WaitOne(_msTimeOut, false))
{
_ComandoMaquina();
}
}
}
}
public partial class Form1 : Form
{
MegaAPI tty;
UIThread.T0_Thread thr1;
UIThread.T0_SyncEvents thrE1;
Thread Thread1;
int ACount1 = 0;
void UIUpdate1()
{
lock (tty)
{
ACount1 = tty.SomeStupidBlockingFunction(ACount1);
}
this.BeginInvoke((Action)delegate { txtAuto1.Text = ACount1.ToString(); });
}
UIThread.T0_Thread thr2;
UIThread.T0_SyncEvents thrE2;
Thread Thread2;
int ACount2 = 0;
void UIUpdate2()
{
lock (tty)
{
ACount2 = tty.SomeStupidBlockingFunction(ACount2);
}
this.BeginInvoke((Action)delegate { txtAuto2.Text = ACount2.ToString(); });
}
UIThread.T0_Thread thr3;
UIThread.T0_SyncEvents thrE3;
Thread Thread3;
int ACount3 = 0;
void UIUpdate3()
{
lock (tty)
{
ACount3 = tty.SomeStupidBlockingFunction(ACount3);
}
this.BeginInvoke((Action)delegate { txtAuto3.Text = ACount3.ToString(); });
}
UIThread.T0_Thread thr4;
UIThread.T0_SyncEvents thrE4;
Thread Thread4;
int ACount4 = 0;
void UIUpdate4()
{
lock (tty)
{
ACount4 = tty.SomeStupidBlockingFunction(ACount4);
}
this.BeginInvoke((Action)delegate { txtAuto4.Text = ACount4.ToString(); });
}
public Form1()
{
InitializeComponent();
tty = new MegaAPI();
thrE1 = new UIThread.T0_SyncEvents();
thr1 = new UIThread.T0_Thread(thrE1, UIUpdate1, 500);
Thread1 = new Thread(thr1.VaiRodar);
Thread1.Start();
thrE2 = new UIThread.T0_SyncEvents();
thr2 = new UIThread.T0_Thread(thrE2, UIUpdate2, 500);
Thread2 = new Thread(thr2.VaiRodar);
Thread2.Start();
thrE3 = new UIThread.T0_SyncEvents();
thr3 = new UIThread.T0_Thread(thrE3, UIUpdate3, 500);
Thread3 = new Thread(thr3.VaiRodar);
Thread3.Start();
thrE4 = new UIThread.T0_SyncEvents();
thr4 = new UIThread.T0_Thread(thrE4, UIUpdate4, 500);
Thread4 = new Thread(thr4.VaiRodar);
Thread4.Start();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
thrE1.EventFecharThread.Set();
thrE2.EventFecharThread.Set();
thrE3.EventFecharThread.Set();
thrE4.EventFecharThread.Set();
Thread1.Join();
Thread2.Join();
Thread3.Join();
Thread4.Join();
}
int Mcount = 0;
private void btManual_Click(object sender, EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
lock (tty) // locks here ! Never runs inside! But the other threads keep counting..
{
Mcount = tty.SomeStupidBlockingFunction(Mcount);
txtManual.Text = Mcount.ToString();
}
Cursor.Current = Cursors.Default;
}
}
I suspect you are hitting something with the Windows message loop and threading in WinForms. I don't know what that is, but here are a few pointers:
You can run the button's task in a backgroundWorker to keep the work off the UI thread. That solves the lock problem. Drag a BackgroundWorker from the toolbox and drop it on your Form in the designer, and hook up the event, i.e.:
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
then switch your code in btManual_Click to call the background worker like this:
backgroundWorker1.RunWorkerAsync();
and then:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Mcount = tty.SomeStupidBlockingFunction(Mcount);
this.BeginInvoke((Action)delegate { txtManual.Text = Mcount.ToString(); });
}
I've left out the lock (tty) because I would rather see only one of these statements inside the function, rather than five of them outside. And instead of locking on tty, I would create a private variable like this:
public class MegaAPI
{
private object sync = new object();
public int SomeStupidBlockingFunction(int c)
{
lock (this.sync)
{
Thread.Sleep(800);
return ++c;
}
}
}
Everywhere else is then simplified, for example:
void UIUpdate1()
{
ACount1 = tty.SomeStupidBlockingFunction(ACount1);
this.BeginInvoke((Action)delegate { txtAuto1.Text = ACount1.ToString(); });
}
And since you can't run the background worker while it's still processing, here is a quick-and-dirty solution: disable the button while it's working:
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
and then:
private void btManual_Click(object sender, EventArgs e)
{
this.btManual.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
and:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.btManual.Enabled = true;
}
So I recommend:
Keep a single lock () statement
inside the function needing the
synchronization
Keep the lock object private
Run the work on a background worker
Mutexes do not provide fairness by default. They just guarantee that your process as a whole will make forward progress. It is the implementation's job to pick the best thread to get the mutex based on characteristics of the scheduler and so on. It is the coder's job to make sure that the thread that gets the mutex does whatever work the program needs done.
If it's a problem for you if the "wrong thread" gets the mutex, you are doing it wrong. Mutexes are for cases where there is no "wrong thread". If you need fairness or predictable scheduling, you need to use a locking primitive that provides it or use thread priorities.
Mutexes tend to act in strange ways when threads that hold them aren't CPU-limited. Your threads acquire the mutex and then deschedule themselves. This will lead to degenerate scheduling behavior just like the behavior you're seeing. (They won't break their guarantees, of course, but they will act much less like a theoretically perfect mutex that also provided things like fairness.)