I stop a thread execution with .Abort() and .Join() for wait the thread terminates. But the problem is that .Join() never unblock application, same when thread was terminated. Why? my code:
th.Abort();
Console.WriteLine("request sent, please wait..");
th.Join();
Console.WriteLine("done!");
the above code never unlock application, but it works fine:
th.Abort();
Console.WriteLine("request sent, please wait..");
while (serverTh.ThreadState != ThreadState.Aborted) {
Thread.Sleep(500);
}
Console.WriteLine("done!");
Thanks in advance.
What's going on in the thread that you are trying to abort? For instance, this works fine:
public static void Main(String[] args)
{
var t = new Thread(LoopForever);
t.Start();
Thread.Sleep(500);
Console.WriteLine("request sent, please wait..");
t.Abort();
t.Join();
Console.WriteLine("done!");
Console.ReadLine();
}
public static void LoopForever()
{
Console.WriteLine("Running!");
while (true)
{
Thread.Sleep(100);
Console.WriteLine("Running!");
}
}
The only thing that comes to mind is maybe your background thread is catching the AbortException and then calling ResetAbort on itself:
public static void Main(String[] args)
{
var t = new Thread(LoopForever);
t.Start();
// Let the thread get started...
Thread.Sleep(500);
Console.WriteLine("request sent, please wait..");
t.Abort();
t.Join();
Console.WriteLine("done!");
Console.ReadLine();
}
public static void LoopForever()
{
Console.WriteLine("Running!");
while (true)
{
try
{
Console.WriteLine("Running!");
Thread.Sleep(100);
}
catch (ThreadAbortException ex)
{
Console.WriteLine("Alas, I was aborted!");
Thread.ResetAbort();
Console.WriteLine("But behold, I live!");
}
}
}
Related
Why does this code not reach the Console.WriteLine("Other thread is done!"); ? This code is from Pro C# 5.0 and the .NET 4.5 Framework book, pg 717-718.
private static AutoResetEvent waitHandle = new AutoResetEvent(false);
static void Main(string[] args)
{
Console.WriteLine("ID of thread in Main(): {0}", Thread.CurrentThread.ManagedThreadId);
AddParms data = new AddParms(3, 4);
Thread t = new Thread(new ParameterizedThreadStart(Add));
t.Start(data);
waitHandle.WaitOne();
Console.WriteLine("Other thread is done!");
Console.ReadLine();
}
private static void Add(object data)
{
Console.WriteLine("ID of thread in Add(): {0}", Thread.CurrentThread.ManagedThreadId);
AddParms ap = (AddParms)data;
Console.WriteLine("{0} + {1} = {2}", ap.A, ap.B, ap.A + ap.B);
}
waitHandle.WaitOne();
This line causes the execution to stop until the wait handle is set.
The provided code never sets that wait handle, and thus the code blocks indefinitely.
I'm playing around with async-await and cancellation to get some more understanding on the matter. For this I have made the following console application:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncTest
{
class Program
{
private static CancellationTokenSource _cancellationTokenSource;
private static CancellationToken _cancellationToken;
static void Main(string[] args)
{
Console.CancelKeyPress += myHandler;
_cancellationTokenSource = new CancellationTokenSource();
_cancellationToken = _cancellationTokenSource.Token;
var task = DoWorkAsync(_cancellationToken).ContinueWith(ContinueMethod);
task.Wait();
Console.ReadLine();
}
protected static void myHandler(object sender, ConsoleCancelEventArgs args)
{
if (_cancellationToken.CanBeCanceled)
{
_cancellationTokenSource.Cancel();
}
args.Cancel = true;
}
static void ContinueMethod(Task task)
{
if (task.IsCanceled)
{
Console.WriteLine("The task was canceled");
}
if (task.IsCompleted)
{
Console.WriteLine("The task completed successfully");
}
if (task.IsFaulted)
{
if (task.Exception != null)
{
var exceptions = task.Exception.Flatten().InnerExceptions;
foreach (var exception in exceptions)
{
Console.WriteLine(exception.Message);
}
}
Console.WriteLine("The task failed");
}
}
static async Task DoWorkAsync(CancellationToken cancellationToken)
{
await Task.Run(() => DoWork(cancellationToken), cancellationToken);
}
static void DoWork(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Console.WriteLine("DoWork() is started");
// Uncomment the following line of code to put the task in a 'faulted' state
//throw new Exception();
for (var count = 0; count < 10; count++)
{
if (cancellationToken.IsCancellationRequested)
{
Console.WriteLine("Get a cancelation request");
cancellationToken.ThrowIfCancellationRequested();
}
else
{
Thread.Sleep(500);
Console.WriteLine("Count : " + count);
}
}
Console.WriteLine("DoWork() is finished");
}
}
}
When I let the application complete, I correctly receive the "The task completed successfully" message.
Now when I press CTRL+C, which triggers a cancel on the started task (see interception through myHandler), I correctly get the "The task was canceled" message. But I also get the "The task completed successfully" message. I was not expecting the task to also show up as complete, since I canceled it.
In case I uncomment the throw new Exception(); line in the DoWork() method, I correctly receive the "The task failed" message, but also the "The task completed successfully" message.
Am I wrong in my assumption and is this as designed? Or am I missing something else entirely?
I could off course work around this by adding an additional check as follows:
if (task.IsCompleted && !task.IsCanceled)
{
Console.WriteLine("The task completed successfully");
}
But I'm not sure if this is the correct way or if something else in my program is causing this completed state.
Thanks in advance for your input and/or clarification on this matter.
The documentation of Task.IsCompleted says
IsCompleted will return true when the task is in one of the three final states: RanToCompletion, Faulted, or Canceled.
So IsCompleted tells you at least that the Task is not running any more. It does not indicate if the Task completed successfully, failed or was cancelled.
Use Task.IsCompletedSuccessFully
I want run a thread continuously. This thread would poll and check for card status. Here is a sample implementation:
static void Main(string[] args)
{
var _cancelationTokenSource = new CancellationTokenSource();
new Task(() => chkRequestTask(_cancelationTokenSource), _cancelationTokenSource.Token, TaskCreationOptions.LongRunning).Start();
while (true)
{
}
}
static bool chkRequestTask(CancellationTokenSource _cancellationTokenSource)
{
bool noRequest = false;
while (!_cancellationTokenSource.Token.IsCancellationRequested)
{
var RequestTask = Task.Factory.StartNew(() => noRequest = chkRequestTask(_cancellationTokenSource), _cancellationTokenSource.Token);
if (noRequest)
{
_cancellationTokenSource.Token.WaitHandle.WaitOne(15000);
Console.WriteLine("Waiting for 15Seconds");
}
else
{
Console.WriteLine("Checking the card");
}
}
return noRequest;
}
What I want to achieve here is chkRequestTask should be run on a separate thread. This would continously poll the status of the card. For this sample I'm simply doing : Console.WriteLine("Checking the card");.
Once it checks the status of the card it should sleep for 15secs for this sample only (in general it should check every 50ms, but for testing purposes I have kept 15secs).
But in the above sample it's not sleeping it's simply giving me Checking the card continuously. It's not sleeping at all for 15secs. What is wrong with this code ?
You're calling chkRequestTask recursively using Task.Factory.StartNew which you don't need at all.
It's not clear why you need to poll the status, better idea is to check any event or callback or WaitHandle provided by the card API you're talking about. That should keep you away from the pain.
If at all you believe polling is the only option you've left with, you can do it as follows.
static async Task ChkRequestTask(CancellationToken token)
{
while (true)
{
token.ThrowIfCancellationRequested();
Console.WriteLine("Checking the card");
bool status = PollTheCardForStatus();
if(!status)
break;
await Task.Delay(15 * 1000, token);//Adjust the delay as you wish
}
}
Else where in code, if possible await the call, If not then attach a continuation or use blocking task.Wait.
await ChkRequestTask(token);
This method doesn't need to return bool as you're returning from the method only when it is false, it is safe to assume the status is false when the Task returned from ChkRequestTask completes, which means poll returned false or the CancellationToken is cancelled, in which case you'll get TaskCanceledException
This is how I have done this. It seems to be working properly. As it's a background thread it would exit when the application exits. Could someone advise If this is the right way to do it.
private void Form1_Load(object sender, EventArgs e)
{
m_dev = DASK.Register_Card(DASK.PCI_7250, 0);
if (m_dev < 0)
{
MessageBox.Show("Register_Card error!");
}
FunctionToCall();
}
private void FunctionToCall()
{
short ret;
uint int_value;
var thread = new Thread(() =>
{
while (true)
{
ret = DASK.DI_ReadPort((ushort)m_dev, 0, out int_value);
if (ret < 0)
{
MessageBox.Show("D2K_DI_ReadPort error!");
return;
}
if (int_value > 0)
{
textBox2.Invoke(new UpdateText(DisplayText), Convert.ToInt32(int_value));
}
Thread.Sleep(500);
}
});
thread.Start();
thread.IsBackground = true;
}
private void DisplayText(int i)
{
textBox2.Text = i.ToString();
}
I am starting a thread and updating form element but following code is making form unresposive please suggest what I am doing wrong here.
private void StartTimer()
{
Thread t = new Thread(Updates);
t.IsBackground = true;
t.Start();
}
private void Updates()
{
try
{
while (true)
{
this.Invoke((MethodInvoker)delegate
{
lblTotalImages.Text = AppHelper.GetTotalCount(textBox1.Text).ToString();
if (sitename != null)
{
lblTotalPosted.Text = AppHelper.GetPostedCount(sitename).ToString();
// Application.DoEvents();
}
});
Thread.Sleep(1000);
}
}
catch (Exception ex)
{
}
}
Edit-------
Thanks #Servy for introducing Task Parallel Library i have never used it here is solution i come up with i used timer and task factory
ya for .net 4 without library extension and vs 2010 i have this working perfectly
enter code here private void timer1_Tick(object sender, EventArgs e)
{
Task.Factory.StartNew(() => AppHelper.GetTotalCount(textBox1.Text)).ContinueWith(t => lblTotalImages.Text = t.Result.ToString(), TaskScheduler.FromCurrentSynchronizationContext());
if (sitename != null)
{
Task.Factory.StartNew(() => AppHelper.GetPostedCount(sitename)).ContinueWith(t => lblTotalPosted.Text = t.Result.ToString(), TaskScheduler.FromCurrentSynchronizationContext());
}
}
You are doing some sort of long running non-UI operation inside of the call to Invoke, which means it's being done in the UI thread. You should strive to only be updating the UI in the UI thread; ensure that any long running non-UI code is outside of any invocations to the UI thread.
The use of await also allows this solution to be written in a much simpler and more effective manor:
public async void StartTimer()
{
while (true)
{
string text = textBox1.Text;
lblTotalImages.Text = await Task.Run(() =>
AppHelper.GetTotalCount(text).ToString());
if (sitename != null)
{
lblTotalPosted.Text = await Task.Run(() =>
AppHelper.GetPostedCount(sitename).ToString());
}
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
I have 1 class (acBL) which handles 2 threads (fpDoWork). Any work that is done in fpDoWork will trigger an event back to the acBL class. On my form I declare the acBL class and associate Event handlers on acBL - this way whenever the event is called, it 'should' update the UI with changes.
What is not happening is, when each fpDoWork thread is started, it performs the operations, the ProcessingEvent is called and does go into the frmMain.handlerProcessing1 event. It gets to the point where this.BeginInvoke(new Processing2Event (handlerProcessing2), status) is called, then it just hangs and waits until the thread has finished its work before continuing to update the UI. I tried this.Invoke, but that method just seems to hang. Any ideas?
Code inside frmMain
Earlier in the code:
this.acBL.Processing1Event += new acBL.Processing1(handlerProcessing1);
this.acBL.Processing2Event += new acBL.Processing2(handlerProcessing2);
Handlers:
private void handlerProcessing1(string status) {
if (InvokeRequired) {
this.BeginInvoke(new MethodInvoker(this.Refresh));
this.BeginInvoke(new Processing1Event (handlerProcessing1), status);
}
else {
Console.WriteLine("UPDATING 1: "+status);
lblForProcessing1.Text = status;
this.Refresh();
return;
}
}
private void handlerProcessing2(string status) {
if (InvokeRequired) {
this.BeginInvoke(new MethodInvoker(this.Refresh));
this.BeginInvoke(new Processing2Event (handlerProcessing2), status);
}
else {
Console.WriteLine("UPDATING 2: "+status);
lblForProcessing2.Text = status;
this.Refresh();
return;
}
}
Code inside acBL
In a main method:
bool thread1Complete = false;
fpDoWork fpDoWork1 = new fpDoWork();
fpDoWork1.GUIForm = frmMain;
fpDoWork1.ProcessingEvent += new fpDoWork.Processing(handlerProcessing1Event);
fpDoWork1.ThreadCompleteEvent += new fpDoWork.ThreadComplete(thread1Complete);
Thread fpDoWork1Thread= new Thread(new ThreadStart(fpDoWork1.StartWork));
bool thread2Complete = false;
fpDoWork fpDoWork2 = new fpDoWork();
fpDoWork2.GUIForm = frmMain;
fpDoWork2.ProcessingEvent += new fpDoWork.Processing(handlerProcessing2Event);
fpDoWork2.ThreadCompleteEvent += new fpDoWork.ThreadComplete(thread2Complete);
Thread fpDoWork2Thread= new Thread(new ThreadStart(fpDoWork2.StartWork));
Console.WriteLine("Work for 1 Thread started...");
fpDoWork1Thread.Start();
Console.WriteLine("Work for 2 Thread started...");
fpDoWork2Thread.Start();
while (!thread1Complete && !thread2Complete ) {
if (!thread1Complete && !thread2Complete ) {
Console.WriteLine("Waiting for both copying threads...");
}
else if (!thread1Complete && thread2Complete ) {
Console.WriteLine("Waiting for thread 1...");
}
else if (thread1Complete && !thread2Complete ) {
Console.WriteLine("Waiting for thread 2...");
}
Thread.Sleep(1000);
}
Console.WriteLine("All done");
Else where in the code:
public delegate void ProcessingFor1 (string filename);
public delegate void ProcessingFor2 (string filename);
public event ProcessingFor1 ProcessingEventFor1;
public event ProcessingFor2 ProcessingEventFor2;
private void handlerProcessing1Event(string filename) {
Console.WriteLine("Processing 1: " + filename);
ProcessingEventFor1(filename);
}
private void handlerProcessing1Event(string filename) {
Console.WriteLine("Processing 2: " + filename);
ProcessingEventFor2(filename);
}
the reason your UI is not updating is that the primary UI thread is stuck in your while() loop. BackgroundWorker is your friend
try to avoid creating threads in one thread and sit there waiting for them to finish, its a bad use of threads in the first place
cheers