I have a long running task in a thread. I
Thread a = new Thread(new ThreadStart()({ delegate()
{
Catalog.Generate(); //long running task
}));
a.Start();
Thread b = new Thread(new ThreadStart()({ delegate()
{
if( File.Exists(stopFile) )
{
a.Abort();
}
}));
b.Start();
This stops Thread A when the stop file is created BUT the catalog.generate method still keeps running? How do I end it?
The problem is your thread b starts working and does the check and immediately exits.
You have to add some sort of loop for the thread b to keep running (this is example code not best practice):
Thread b = new Thread(new ThreadStart()({ delegate()
{
int t=0;
while(i<100)
{
if( File.Exists(stopFile) )
{
a.Abort();
}
else
{
i++;
Thread.Sleep(500);
}
}
}));
"Raises a ThreadAbortException in the thread on which it is invoked, to begin the process of terminating the thread. Calling this method usually terminates the thread."
The abort method sends an indicator that the thread should close. It is dependent on the thread processing as to how it handles this, and when it responds. I would suggest that the Catalog.Generate is probably refusing to respond.
Related
I created a Thread, and want to kill him. I found my Thread in Process.GetCurrentProcess().Threads, but it has ProcessThread class, and can't be cast to Thread, so i can't kill him.
foreach (Thread thread in currentProcess.Threads)//throw error:unable to cast
{
if (thread.ManagedThreadId.Equals(processThreadId))
{
thread.Abort();
}
}
System.Diagnostics.ProcessThread isn't the same notion than System.Threading.Thread.
A quick solution is to save all task created in ConcurrentBag
int processThreadId = 0;
var threads = new ConcurrentDictionary<int,Thread>();
///...Some action
var newThread = new Thread(()=> {});
newThread.Start();
threads.TryAdd(newThread.ManagedThreadId,newThread);
///...Some action
Thread thread = null;
if(threads.TryRemove(processThreadId,out thread)){
thread.Abort();
}
It seems possible to translate ManagedThreadId into NativeThreadId
for more information Getting the thread ID from a thread
I am in a situation where I have to spawn a new thread manually, so I am able to can call .SetApartmentState(ApartmentState.STA). This means (as far as I know) that I cannot use Task. But I would like to know when the thread was done running, something like the await which works with async. However, the best I can come up with is a loop, constantly checking Thread.IsAlive, like this:
var thread = new Thread(() =>
{
// my code here
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
while(thread.IsAlive)
{
// Wait 100 ms
Thread.Sleep(100);
}
This should work (as long as the thread don't end up stalling), but it seems kind of clumsy. Isn't there a more clever way to check when the thread is done (or dead)?
It is only to avoid blocking the GUI thread, so any minor performance hits are fine (like some hundred milliseconds).
Here is an extension method you could use to enable the awaiting of threads (inspired from this article: await anything).
public static TaskAwaiter GetAwaiter(this Thread thread)
{
return Task.Run(async () =>
{
while (thread.IsAlive)
{
await Task.Delay(100).ConfigureAwait(false);
}
}).GetAwaiter();
}
Usage example:
var thread = new Thread(() =>
{
Thread.Sleep(1000); // Simulate some background work
});
thread.IsBackground = true;
thread.Start();
await thread; // Wait asynchronously until the thread is completed
thread.Join(); // If you want to be extra sure that the thread has finished
Could you use the BackgroundWorker class? It has an event that reports when its finished.
I am using thread to multi tasks in winform solution, trying to abort the thread while its working but its not aborting, here is , is there any solution for this situation? need to make the thread abort/quit smoothly without any issues !
also is there any idea of how I can make the thread pause/resume?
Thanks in advance!
Thread CommentingThread;
CommentingThread = new Thread(async () =>
{
AddLog("Commenting process has been started!");
if (CommentBTN.InvokeRequired)
{
CommentBTN.Invoke((MethodInvoker)delegate () {
CommentBTN.Text = "Stop"; });
}
else
{
CommentBTN.Text = "Stop";
}
if (UrlListview.InvokeRequired)
{
if (UrlListview.InvokeRequired)
{
UrlListview.Invoke((MethodInvoker)async delegate ()
{
foreach (ListViewItem item in UrlListview.Items)
{
XtraMessageBox.Show(item.Text);
int timetodelay = RandomNumber.Next(int.Parse(CommentsMinDelayNumric.Value.ToString()), int.Parse(CommentsMaxDelayNumric.Value.ToString()));
await Task.Run(async () =>
{
await Task.Delay(timetodelay * 1000);
});
}
CommentBTN.Text = "Start";
AddLog("Commenting process has been finished sucessfully!");
});
}
}
else
{
foreach (ListViewItem item in UrlListview.Items)
{
XtraMessageBox.Show(item.Text);
int timetodelay = RandomNumber.Next(int.Parse(CommentsMinDelayNumric.Value.ToString()), int.Parse(CommentsMaxDelayNumric.Value.ToString()));
await Task.Run(async () =>
{
await Task.Delay(timetodelay * 1000 );
});
}
CommentBTN.Text = "Start";
AddLog("Commenting process has been finished sucessfully!");
}
#endregion
});
CommentingThread.Start();
if (CommentBTN.Text == "Stop")
{
CommentBTN.Text = "Start";
CommentingThread.Abort();
AddLog("Commenting process has been stopped!");
}
First of all, looking at your code, it seems that the Thread may stop immediately if UrlListview.Items does not contain any elements. You might be missing a while loop in this case.
Regarding the issue of stopping the thread:
Calling CommentingThread.Abort() will raise a ThreadAbortException which effectively crashes the thread (see the Microsoft Docs for more info for more info.
To shut a thread down gracefully you should either declare CancellationTokenSource or a boolean which can be set to true (or false, depending on your implementation), to notify the thread that it needs to be stopped. Here is an example:
var myThread_ctoks = new CancellationTokenSource();
Thread myThread = new Thread( async () =>
{
while (!myThread_ctoks.IsCancellationRequested) // simulate many long actions
{
await Task.Delay(TimeSpan.FromSeconds(2));
Console.WriteLine("Iteration finished!");
}
});
myThread.Start(); // start the thread
await Task.Delay(TimeSpan.FromMinutes(1)); // lets do some other work
myThread_ctoks.Cancel(); // and now shut down the thread
This thread checks every 2 seconds if a shutdown is required (because the simulated action takes that long). As soon as cancellation is requested (myThread_ctoks.IsCancellationRequested is set to true), the while condition will be false and thus the thread will end.
The benefit of doing it this way is that the thread will be shut down in a safe, defined way as it actually shuts down gracefully and doesn't crash.
Regarding how you could pause and resume a thread. You could also use a variable to control that, just by checking if the thread is allowed to do work or not. If it should pause then you would just wait for a second in a while loop.
There is also the possibility to use Thread.Suspend() and Thread.Resume(). There is however the possibility, according to Microsoft that you could lock up other threads under certain circumstances. Additionally, you do not know exactly what code is being executed when you interrupt it. Which may lead to further unexpected behaviour.
Thats why I am thinking its best to use a variable to control the thread behaviour.
I have a long running method and I want to add timeout into it. Is it feasible to do that? Something like:
AbortWaitSeconds(20)
{
this.LongRunningMethod();
}
Where when it reached 20 seconds, the method will be aborted. The method doesn't have loop and I do not have a control/code over that method.
try this
class Program
{
static void Main(string[] args)
{
if (RunWithTimeout(LongRunningOperation, TimeSpan.FromMilliseconds(3000)))
{
Console.WriteLine("Worker thread finished.");
}
else
{
Console.WriteLine("Worker thread was aborted.");
}
}
static bool RunWithTimeout(ThreadStart threadStart, TimeSpan timeout)
{
Thread workerThread = new Thread(threadStart);
workerThread.Start();
bool finished = workerThread.Join(timeout);
if (!finished)
workerThread.Abort();
return finished;
}
static void LongRunningOperation()
{
Thread.Sleep(5000);
}
}
you can see it
See my answer to this question for a generic solution.
Do the calculation in a background thread and wait until the thread finishes. To abort calculation, use Thread.Abort(), this will throw a ThreadAbortException in the calculation thread.
You can only abort long running process from the same thread if you have a code point in which to introduce a check and exit. This is because - clearly - the thread is busy, so it can't process checks to abort itself. So, your example which only contains one call to 'LongRunningMethod' could not be aborted from the same thread. You'd need to show more code in order to get direction on that.
As a general rule, long-running tasks are best sent to different threads (e.g; via a BackgroundWorker or new Thread) so they can be aborted.
Here is a simple way to do this;
private void StartThread()
{
Thread t = new Thread(LongRunningMethod);
t.Start();
if (!t.Join(10000)) // give the operation 10s to complete
{
// the thread did not complete on its own, so we will abort it now
t.Abort();
}
}
private void LongRunningMethod()
{
// do something that'll take awhile
}
Since you have no control over that code I believe the correct approach would be to run that code using WaitHandles and the ThreadPool:
WaitHandle waitHandle = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(<long running task delegate>), waitHandle);
WaitHandle.WaitAll(new[]{ waitHandle }, <timeout>);
Here you can find more info on how WaitHandle works.
let's say we have some simple code like this :
private static void Main()
{
Console.WriteLine("Main thread {0}\n", Thread.CurrentThread.ManagedThreadId);
Action asyncCaller1 = () => LongPerfomingTask(5);
Action asyncCaller2 = () => LongPerfomingTask(3);
var asyncResult1 = asyncCaller1.BeginInvoke(null, null);
var asyncResult2 = asyncCaller2.BeginInvoke(null, null);
asyncResult1.AsyncWaitHandle.WaitOne();
asyncResult2.AsyncWaitHandle.WaitOne();
Console.WriteLine("Done");
}
private static void LongPerfomringTask(int seconds)
{
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("Thread {0} finished execution", Thread.CurrentThread.ManagedThreadId);
}
Delegate.BeginInvoke() does not create a thread, It's executing code in a caller's thread when it is in idle state, right?So, why the output of this sample application is like this :
Main thread 1
Thread 4 finished execution
Thread 3 finished execution
Done
No, Delegate.BeginInvoke uses the thread pool. Always. There's no concept of "executing in the caller's thread when it's idle" unless you're thinking of adding tasks to a UI message queue... were you getting confused with Control.BeginInvoke / Dispatcher.BeginInvoke?
In this case you've got a console app - there's no message pumping going on to start with.
#taras.roshko: Here's a resource to boost your understanding of ThreadPool:
Chapter on Threading