Task deadlock doesn't occur - c#

I found this example in the book. And it's written that this code leads to deadlock. But I don't get it and don't understand why it should be?
I always get
“Locked B and A”
“Locked A and B”
static void Main()
{
object lockA = new object();
object lockB = new object();
var up = Task.Run(() =>
{
lock (lockA)
{
Thread.Sleep(1000);
lock (lockB)
{
Console.WriteLine(“Locked A and B”);
}
}
});
lock (lockB)
{
lock (lockA)
{
Console.WriteLine(“Locked B and A”);
}
}
up.Wait();
Console.ReadLine();
}

The code isn't guaranteed to deadlock. There is a race condition as to whether or not it will deadlock. If the newly started task manages to grab the first lock before the main thread goes on to grab that same lock, then the code deadlocks, if (as is no doubt happening for you) the first thread manages to get both locks before the worker thread does anything, then there is no deadlock.

Related

Can a second thread enter the same critical section just because the first thread called Monitor.Wait using the same sync lock?

Please tell me if I am thinking it alright.
A different thread cannot enter the same critical section using
the same lock just because the first thread called Monitor.Wait, right? The Wait method only allows a different thread to acquire
the same monitor, i.e. the same synchronization lock but only for a different critical section and never for the same critical
section.
Is my understanding correct?
Because if the Wait method meant that anyone can now enter this
same critical section using this same lock, then that would defeat
the whole purpose of synchronization, right?
So, in the code below (written in notepad, so please forgive any
typos), ThreadProc2 can only use syncLock to enter the code in
ThreadProc2 and not in ThreadProc1 while the a previous thread
that held and subsequently relinquished the lock was executing
ThreadProc1, right?
Two or more threads can use the same synchronization lock to run
different pieces of code at the same time, right? Same question as
above, basically, but just confirming for the sake of symmetry with
point 3 below.
Two or more threads can use a different synchronization lock to
run the same piece of code, i.e. to enter the same critical section.
Boilerplate text to correct the formatting.
class Foo
{
private static object syncLock = new object();
public void ThreadProc1()
{
try
{
Monitor.Enter(syncLock);
Monitor.Wait(syncLock);
Thread.Sleep(1000);
}
finally
{
if (Monitor.IsLocked(syncLock))
{
Monitor.Exit(syncLock);
}
}
}
public void ThreadProc2()
{
bool acquired = false;
try
{
// Calling TryEnter instead of
// Enter just for the sake of variety
Monitor.TryEnter(syncLock, ref acquired);
if (acquired)
{
Thread.Sleep(200);
Monitor.Pulse(syncLock);
}
}
finally
{
if (acquired)
{
Monitor.Exit(syncLock);
}
}
}
}
Update
The following illustration confirms that #3 is correct although I don't think it will be a nice thing to do.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace DifferentSyncLockSameCriticalSection
{
class Program
{
static void Main(string[] args)
{
var sathyaish = new Person { Name = "Sathyaish Chakravarthy" };
var superman = new Person { Name = "Superman" };
var tasks = new List<Task>();
// Must not lock on string so I am using
// an object of the Person class as a lock
tasks.Add(Task.Run( () => { Proc1(sathyaish); } ));
tasks.Add(Task.Run(() => { Proc1(superman); }));
Task.WhenAll(tasks);
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
static void Proc1(object state)
{
// Although this would be a very bad practice
lock(state)
{
try
{
Console.WriteLine((state.ToString()).Length);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
class Person
{
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
}
When a thread calls Monitor.Wait it is suspended and the lock released. This will allow another thread to acquire the lock, update some state, and then call Monitor.Pulse in order to communicate to other threads that something has happened. You must have acquired the lock in order to call Pulse. Before Monitor.Wait returns the framework will reacquire the lock for the thread that called Wait.
In order for two threads to communicate with each other they need to use the same synchronization primitive. In your example you've used a monitor, but you usually need to combine this with some kind of test that the Wait returned in response to a Pulse. This is because it is technically possible to Wait to return even if Pulse wasn't called (although this doesn't happen in practice).
It's also worth remembering that a call to Pulse isn't "sticky", so if nobody is waiting on the monitor then Pulse does nothing and a subsequent call to Wait will miss the fact that Pulse was called. This is another reason why you tend to record the fact that something has been done before calling Pulse (see the example below).
It's perfectly valid for two different threads to use the same lock to run different bits of code - in fact this is the typical use-case. For example, one thread acquires the lock to write some data and another thread acquires the lock to read the data. However, it's important to realize that they don't run at the same time. The act of acquiring the lock prevents another thread from acquiring the same lock, so any thread attempting to acquire the lock when it is already locked will block until the other thread releases the lock.
In point 3 you ask:
Two or more threads can use a different synchronization lock to run
the same piece of code, i.e. to enter the same critical section.
However, if two threads are using different locks then they are not entering the same critical section. The critical section is denoted by the lock that protects it - if they're different locks then they are different sections that just happen to access some common data within the section. You should avoid doing this as it can lead to some difficult to debug data race conditions.
Your code is a bit over-complicated for what you're trying to accomplish. For example, let's say we've got 2 threads, and one will signal when there is data available for another to process:
class Foo
{
private readonly object syncLock = new object();
private bool dataAvailable = false;
public void ThreadProc1()
{
lock(syncLock)
{
while(!dataAvailable)
{
// Release the lock and suspend
Monitor.Wait(syncLock);
}
// Now process the data
}
}
public void ThreadProc2()
{
LoadData();
lock(syncLock)
{
dataAvailable = true;
Monitor.Pulse(syncLock);
}
}
private void LoadData()
{
// Gets some data
}
}
}

Create Thread that wait until var change

I want to have a single thread, that consuming from a queue and multiple threads, producing work and placing it on this queue - and then allowing the original producing threads be able to wait (at some point) for that work to have been done and continue working with the object.
somthing like this:
loop:
1. TheThread waiting for "myObj pending" is not null.
2. Thread2 changing "pending" object.
3.1. TheThread do some stuff on "pending"
3.2. Thread2 doing some another stuff.
4. Thread2 waiting until Thread finished, and then do something on "pending" and return him to be null
[there is many "Thread"s like "Thread2", and I want it to be ThreadSafe]
I tryied to do it in the code below, but this is my first time using Threads, so I don't realy sure what am I doing wrong, and if there is an efficient way.
ManualResetEvent mre = new ManualResetEvent(false);
myObj pending = null;
Thread worker = new Thread(doWork);
Thread.start();
Thread Thread2 = new Thread(anotherMethod);
Thread Thread3 = new Thread(anotherMethod2);
void doWork()
{
while (true)
{
if (pending == null)
{
mre.waitOne()
}
lock(pending)
{
pending.doSomething();
mre = new ManualResetEvent(false);
}
}
}
void anotherMethod()
{
//doStuff
pending = new myObj()
mre.set();
//doStuff
worker.Join()
pending.doSomeThingJustIfDoWorkDone()
}
void anotherMethod2()
{
//doStuff
pending = new myObj()
mre.set();
//doStuff
worker.Join()
pending.doSomeThingJustIfDoWorkDone()
}
When working with threads I prefer to use Tasks to manage them.
I think that the method ContinueWith in the Task Parallel Library, is the one you are looking for. Take a look at this examples, maybe this could help you.
http://msdn.microsoft.com/en-us/library/dd537612.aspx
There is ConcurrentExclusiveSchedulerPair in 4.5 that does exactly what you want.
In general, your use case is described in Richter's book "CLR via C#" and is called Condition In variable pattern.
internal sealed class ConditionVariablePattern {
private readonly Object m_lock = new Object();
private Boolean m_condition = false;
public void Thread1() {
Monitor.Enter(m_lock); // Acquire a mutual-exclusive lock
// While under the lock, test the complex condition "atomically"
while (!m_condition) {
// If condition is not met, wait for another thread to change the condition
Monitor.Wait(m_lock); // Temporarily release lock so other threads can get it
}
// The condition was met, process the data...
Monitor.Exit(m_lock); // Permanently release lock
}
public void Thread2() {
Monitor.Enter(m_lock); // Acquire a mutual-exclusive lock
// Process data and modify the condition...
m_condition = true;
// Monitor.Pulse(m_lock); // Wakes one waiter AFTER lock is released
Monitor.PulseAll(m_lock); // Wakes all waiters AFTER lock is released
Monitor.Exit(m_lock); // Release lock
}
}
You can call worker.Join() to wait until your worker thread completes. You can join multiple threads.
I think you'd be better off using Tasks instead of manually handling threads.
you should lock another object because what you are doing may lead to a deadlock
instead of the pending object it will be better to make something like something like
private readonly Object _myPendingLock = new Object();
and you should lock this object whenever you call pending object
void anotherMethod()
{
lock(_myPendingLock)
//doStuff
pending = new myObj()
mew.set();
//doStuff
[...]
worker.Join()
pending.doSomeThingJustIfDoWorkDone()
}
}
// but if you want the producer consumer in safest maner it will be better to take a look at the built-in class
[ConcurrentQueue Class]

Parallel A* search in C# - Thread sync

I have two threads which use two different functions. First one to search from start to end and the second one to search from end to start.
Now I'm using Thread.Sleep(10) for synchronisation, but it takes too much time, and testing is not possible in such condition.
Any idea how can I sync two threads with different functions?
It depends slightly on what you want to do.
If you have two threads and you just want to exit one when the other reaches "success" (or n threads and you want to exit them all when one reaches "success" first) you just need to periodically check for success on each thread.
Use Interlocked to do this without locks, or some other mechanism (see below)
Use cancellable Task objects
If you need to do your search in phases, where each thread does something and then waits for the other to catch up, you need a different approach.
Use Barrier
Given that you are doing an A*-search you likely need a combination of all two/three anyway:
Barrier to coordinate the steps and update the open set between steps
Success signalling to work out when to exit threads if another thread succeeded
Task objects with CancellationToken to allow callers to cancel the search.
Another answer suggested Semaphore - this is not really suitable for your needs (see comments below).
Barrier can be used for searches such as this by:
enter step 0 of the algorithm
n threads split the current level into equal parts and work on each half, when each completes then it signals and waits for the other thread
when all threads are ready, proceed to the next step and repeat the search
Simple check for exit - Interlocked
The first part is checking for success. If you want to stay "lockless", you can use Interlocked to do this, the general pattern is:
// global success indicator
private const int NotDone = 0;
private const int AllDone = 1;
private int _allDone = NotDone;
private GeneralSearchFunction(bool directionForward) {
bool iFoundIt = false;
... do some search operations that won't take much time
if (iFoundIt) {
// set _allDone to AllDone!
Interlocked.Exchange(ref _allDone, AllDone);
return;
}
... do more work
// after one or a few iterations, if this thread is still going
// see if another thread has set _allDone to AllDone
if (Interlocked.CompareExchange(ref _allDone, NotDone, NotDone) == AllDone) {
return; // if they did, then exit
}
... loop to the top and carry on working
}
// main thread:
Thread t1 = new Thread(() => GeneralSearchFunction(true));
Thread t2 = new Thread(() => GeneralSearchFunction(false));
t1.Start(); t2.Start(); // start both
t1.Join(); t2.Join();
// when this gets to here, one of them will have succeeded
This is the general pattern for any kind of success or cancellation token:
do some work
if you succeed, set a signal every other thread checks periodically
if you haven't yet succeeded then in the middle of that work, either every iteration, or every few iterations, check to see if this thread should exit
So an implementation would look like:
class Program
{
// global success indicator
private const int NotDone = 0;
private const int AllDone = 1;
private static int _allDone = NotDone;
private static int _forwardsCount = 0; // counters to simulate a "find"
private static int _backwardsCount = 0; // counters to simulate a "find"
static void Main(string[] args) {
var searchItem = "foo";
Thread t1 = new Thread(() => DoSearchWithBarrier(SearchForwards, searchItem));
Thread t2 = new Thread(() => DoSearchWithBarrier(SearchBackwards, searchItem));
t1.Start(); t2.Start();
t1.Join(); t2.Join();
Console.WriteLine("all done");
}
private static void DoSearchWithBarrier(Func<string, bool> searchMethod, string searchItem) {
while (!searchMethod(searchItem)) {
// after one or a few iterations, if this thread is still going
// see if another thread has set _allDone to AllDone
if (Interlocked.CompareExchange(ref _allDone, NotDone, NotDone) == AllDone) {
return; // if they did, then exit
}
}
Interlocked.Exchange(ref _allDone, AllDone);
}
public static bool SearchForwards(string item) {
// return true if we "found it", false if not
return (Interlocked.Increment(ref _forwardsCount) == 10);
}
public static bool SearchBackwards(string item) {
// return true if we "found it", false if not
return (Interlocked.Increment(ref _backwardsCount) == 20); // make this less than 10 to find it backwards first
}
}
Using Tasks to the same end
Of course, this wouldn't be .NET 4.5 without using Task:
class Program
{
private static int _forwardsCount = 0; // counters to simulate a "find"
private static int _backwardsCount = 0; // counters to simulate a "find"
static void Main(string[] args) {
var searchItem = "foo";
var tokenSource = new CancellationTokenSource();
var allDone = tokenSource.Token;
Task t1 = Task.Factory.StartNew(() => DoSearchWithBarrier(SearchForwards, searchItem, tokenSource, allDone), allDone);
Task t2 = Task.Factory.StartNew(() => DoSearchWithBarrier(SearchBackwards, searchItem, tokenSource, allDone), allDone);
Task.WaitAll(new[] {t2, t2});
Console.WriteLine("all done");
}
private static void DoSearchWithBarrier(Func<string, bool> searchMethod, string searchItem, CancellationTokenSource tokenSource, CancellationToken allDone) {
while (!searchMethod(searchItem)) {
if (allDone.IsCancellationRequested) {
return;
}
}
tokenSource.Cancel();
}
...
}
However, now you have used the CancellationToken for the wrong things - really this should be kept for the caller of the search to cancel the search, so you should use CancellationToken to check for a requested cancellation (only the caller needs tokenSource then), and a different success synchronisation (such as the Interlocked sample above) to exit.
Phase/step synchronisation
This gets harder for many reasons, but there is a simple approach. Using Barrier (new to .NET 4) in conjunction with an exit signal you can:
Perform the assigned thread's work for the current step, and then wait for the other thread to catch up before doing another iteration
Exit both threads when one succeeds
There are many different approaches for thread sync, depending on exactly what you want to achieve. Some are:
Barrier: This is probably the most suitable if you are intending for both your forwards and backwards searches to run at the same time. It also screams out your intent, i.e. "all threads can't go on until they everyone reaches a barrier"
ManualResetEvent - when one thread releases a signal, all others can proceed until it is set again. AutoResetEvent is similar, except it only allows one thread to proceed before blocking again.
Interlocked - in combination with SpinWait this is a viable lockless solution
Semaphore - possible to use, but not really suited for your scenario
I have only provided a full sample for Barrier here as it seems the most suitable in your case. Barrier is one of the most performant, second only to ManualResetEventSlim (ref. albahari), but using ManualResetEvent will need more complex code.
Other techniques to look at, if none of the above work for you are Monitor.Wait and Monitor.Pulse (now you're using locking) and Task Continuations. The latter is more used for passing data from one async operation to another, but it could be used for your scenario. And, as with the samples at the top of the answer, you are more likely to combine Task with Barrier than use one instead of the other. Task Continuations could be used to do the post-step revision of the open set in the A*-search, but you can just as easily use Barrier for that anyway.
This code, using Barrier works. In essence, DoSearchWithBarrier is the only bit doing the synchronisation - all the rest is setup and teardown code.
class Program {
...
private static int _forwardsCount = 0; // counters to simulate a "find"
private static int _backwardsCount = 0; // counters to simulate a "find"
static void Main(string[] args) {
Barrier barrier = new Barrier(numThreads,
b => Console.WriteLine("Completed search iteration {0}", b.CurrentPhaseNumber));
var searchItem = "foo";
Thread t1 = new Thread(() => DoSearchWithBarrier(SearchForwards, searchItem, barrier));
Thread t2 = new Thread(() => DoSearchWithBarrier(SearchBackwards, searchItem, barrier));
t1.Start(); Console.WriteLine("Started t1");
t2.Start(); Console.WriteLine("Started t2");
t1.Join(); Console.WriteLine("t1 done");
t2.Join(); Console.WriteLine("t2 done");
Console.WriteLine("all done");
}
private static void DoSearchWithBarrier(Func<string, bool> searchMethod, string searchItem, Barrier barrier) {
while (!searchMethod(searchItem)) {
// while we haven't found it, wait for the other thread to catch up
barrier.SignalAndWait(); // check for the other thread AFTER the barrier
if (Interlocked.CompareExchange(ref _allDone, NotDone, NotDone) == AllDone) {
return;
}
}
// set success signal on this thread BEFORE the barrier
Interlocked.Exchange(ref _allDone, AllDone);
// wait for the other thread, and then exit (and it will too)
barrier.SignalAndWait();
}
...
}
There are two things going on here:
Barrier is used to synchronise the two threads so they can't do their next step until the other has caught up
The exit signal uses Interlocked, as I first described.
Implementing this for A* searches is very similar to the above sample. Once all threads reach the barrier and therefore continue you could use a ManualResetEvent or a simple lock to then let one (and only one) revise the open set.
A note on Semaphore
This is probably not what you want as it's most often used when you have a limited pool of resources, with more resource users requiring access than you have resources.
Think of the PlayStation with CoD on it in the corner of the work canteen - 4 controllers, 20 people waiting (WaitOne) to use it, as soon as your character dies you Release the controller and someone else takes your place. No particular FIFO/LIFO ordering is enforced, and in fact Release can be called by the bouncer you employ to prevent the inevitable fights (i.e. thread identity is not enforced).
Simple check for exit - other approaches
Use of lock for simple success indication
You can achieve the same with locking. Both Interlocked and lock ensure you don't see any memory cache issues with reading a common variable between threads:
private readonly object _syncAllDone = new object();
...
if (iFoundIt) {
lock (_syncAllDone) { _allDone = AllDone };
return;
}
...
// see if another thread has set _allDone to AllDone
lock (_syncAllDone) {
if (_allDone == AllDone) {
return; // if they did, then exit
}
}
The disadvantage of this is that locking may well be slower, but you need to test for your situation. The advantage is that if you are using lock anyway to do other things such as writing out results from your thread, you don't have any extra overhead.
Use of ManualResetEvent for simple success indication
This is not really the intended use of reset events, but it can work. (If using .NET 4 or later, use ManualResetEventSlim instead of ManualResetEvent):
private ManualResetEvent _mreAllDone = new ManualResetEvent(true); // will not block a thread
...
if (iFoundIt) {
_mreAllDone.Reset(); // stop other threads proceeding
return;
}
...
// see if another thread has reset _mreAllDone by testing with a 0 timeout
if (!_mreAllDone.WaitOne(0)) {
return; // if they did, then exit
}
Phase synchronisation - other approaches
All of the other approaches get a lot more complex, as you have to do two-way continuation checks to prevent race conditions and permanently blocked threads. I don't recommend them, so I won't provide a sample here (it would be long and complicated).
References:
Interlocked
ManualResetEvent
MSDN - ManualResetEvent and ManualResetEventSlim
Barrier
MSDN - Continuation Tasks
MSDN - Task Cancellation
Semaphore
thread.Join()
is possibly what your after. This will make your current thread block until the other thread ends.
It's possible to Join multiple threads there by syncing all of them to one point.
List<Thread> threads = new List<Thread>();
threads.Add(new Thread(new ThreadStart(<Actual method here>)));
threads.Add(new Thread(new ThreadStart(<Another method here>)));
threads.Add(new Thread(new ThreadStart(<Another method here>)));
foreach(Thread thread in threads)
{
thread.Start();
}
//All your threads are now running
foreach(Thread thread in threads)
{
thread.Join();
}
//You wont get here until all those threads have finished
In some cases You can use AutoResetEvent to wait some result from thread.
You can use Task's for start/stop/wait result of some workers.
You can use Producer/Consumer pattern with BlockingCollection in case your functions eat some data and returns collection of something.

Calling Thread.Sleep() inside lock statement in .net

I was wondering if a call to Threa.Sleep on a thread that already acquiered a Monitor will release the lock before going to sleep:
object o = new object();
Montior.Enter(o);
Thread.Sleep(1000);
Monitor.Exit(o);
While the thread is suspended - can other thread acquire o?
No, the thread won't release the lock before suspending/sleeping
and no other thread will be able to acquire o until the sleeping thread wakes up and releases the locked object
No, the lock will not be released if you Sleep.
If you want to release it, use Monitor.Wait(o, timeout); further, you can also use this to signal from another thread - another thread can use Monitor.Pulse[All] (while holding the lock) to wake the waiting thread earlier than "timeout" (it will re-acquire the lock in the process, too).
Note that whenever using Enter/Exit, you should consider using try/finally too - or you risk not releasing the lock if an exception happens.
Example:
bool haveLock = false;
try {
Monitor.Enter(ref haveLock);
// important: Wait releases, waits, and re-acquires the lock
bool wokeEarly = Monitor.Wait(o, timeout);
if(wokeEarly) {...}
} finally {
if(haveLock) Monitor.Exit(o);
}
Another thread could do:
lock(o) { Monitor.PulseAll(o); }
Which will nudge any threads currently in a Wait on that object (but does nothing if no objects were waking). Emphasis: the waiting thread still has to wait for the pulsing thread to release the lock, since it needs to re-acquire.
No, between Enter and Exit, no other thread can take the lock whatever you do inbetween.
From my experience, calling Thread.Sleep in the middle of a lock block would cause the locking thread to lose the lock (i.e context switch).
I ran the following program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
class Program
{
static void Main(string[] args)
{
Class1 c1 = new Class1();
Class2 c2 = new Class2();
Thread t1 = new Thread(c1.DoSomthing);
Thread t2 = new Thread(c2.DoSomthing);
t1.Start();
Thread.Sleep(500);
t2.Start();
}
}
class Class1
{
object m_objSyncLock = new object();
ManualResetEvent m_objSleep = new ManualResetEvent(true);
public void DoSomthing()
{
Monitor.Enter(m_objSyncLock);
int i = 1; //break point here
Thread.Sleep(565);
i++; //break point here
Monitor.Exit(m_objSyncLock);
}
}
}
class Class2
{
object m_objSyncLock = new object();
public void DoSomthing()
{
lock (m_objSyncLock)
{
int i = 1; //break point here
i++;
}
}
}
Add break points to lines 30, 32, 46 and notice that line 32 occur 1st, then line 48, and only then line 34.
Doesn't this mean that the Thread.Sleep call made me lose my lock?
Moreover, when using ManualResetEvent.WaitOne instead of Thread.Sleep, the executing thread didn't lose exclusivity (except the switch to ManualResetEvent itself).
I'm no guru but this simple test show that Thread.Sleep might make you lose the lock while using ManualResetEvent.WaitOne keeps the lock code block in sync.

Aborting a .NET thread

I am creating a thread A and in that thread creating a new thread B.
So how is the thread hierarchy? Thread B is child of Thread A? Or the threads are created as peers?
I want to abort the parent thread A which in turn kills/aborts its child threads.
How is that possible in C#?
Threads should ideally never be aborted. It simply isn't safe. Consider this as a way of putting down an already sick process. Otherwise, avoid like the plague.
The more correct way of doing this is to have something that the code can periodically check, and itself decide to exit.
An example of stopping threads the polite way:
using System;
using System.Threading;
namespace Treading
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main program starts");
Thread firstThread = new Thread(A);
ThreadStateMessage messageToA = new ThreadStateMessage(){YouShouldStopNow = false};
firstThread.Start(messageToA);
Thread.Sleep(50); //Let other threads do their thing for 0.05 seconds
Console.WriteLine("Sending stop signal from main program!");
messageToA.YouShouldStopNow = true;
firstThread.Join();
Console.WriteLine("Main program ends - press any key to exit");
Console.Read();//
}
private class ThreadStateMessage
{
public bool YouShouldStopNow = false; //this assignment is not really needed, since default value is false
}
public static void A(object param)
{
ThreadStateMessage myMessage = (ThreadStateMessage)param;
Console.WriteLine("Hello from A");
ThreadStateMessage messageToB = new ThreadStateMessage();
Thread secondThread = new Thread(B);
secondThread.Start(messageToB);
while (!myMessage.YouShouldStopNow)
{
Thread.Sleep(10);
Console.WriteLine("A is still running");
}
Console.WriteLine("Sending stop signal from A!");
messageToB.YouShouldStopNow = true;
secondThread.Join();
Console.WriteLine("Goodbye from A");
}
public static void B(object param)
{
ThreadStateMessage myMessage = (ThreadStateMessage)param;
Console.WriteLine("Hello from B");
while(!myMessage.YouShouldStopNow)
{
Thread.Sleep(10);
Console.WriteLine("B is still running");
}
Console.WriteLine("Goodbye from B");
}
}
}
Using Thread.Abort(); causes an exception to be thrown if your thread is in a waiting state of any kind. This is sort of annoying to handle, since there are quite a number of ways that a thread can be waiting. As others have said, you should generally avoid doing it.
Thread.Abort will do what you want, but it is not recommended to abort thread, better choose is to think a way for finishing threads correctly by Thread synchronization mechanism
Here's yet another way to politely signal a thread to die:
Note that this fashion favors finite state automatons where the slave periodically checks for permission to live, then performs a task if allowed. Tasks are not interrupted and are 'atomic'. This works great with simple loops or with command queues. Also this makes sure the thread doesn't spin 100% cpu by giving the slave thread a rest period, set this one to 0 if you don't want any rest in your slave.
var dieEvent = new AutoResetEvent(false);
int slaveRestPeriod = 20;// let's not hog the CPU with an endless loop
var master = new Thread(() =>
{
doStuffAMasterDoes(); // long running operation
dieEvent.Set(); // kill the slave
});
var slave = new Thread(() =>
{
while (!dieEvent.WaitOne(restPeriod))
{
doStuffASlaveDoes();
}
});
slave.Start();
master.Start();
Threads are created as peers, obtain a handle to Thread A and then call ThreadA.Abort()
to forcefully end it. It's better to check a boolean in the thread and if it evaluates to false exit the thread.
public class MyClass
{
public static Thread ThreadA;
public static Thread ThreadB;
private void RunThings()
{
ThreadA = new Thread(new ThreadStart(ThreadAWork));
ThreadB = new Thread(new ThreadStart(ThreadBWork));
ThreadA.Start();
ThreadB.Start();
}
static void ThreadAWork()
{
// do some stuff
// thread A will close now, all work is done.
}
static void ThreadBWork()
{
// do some stuff
ThreadA.Abort(); // close thread A
// thread B will close now, all work is done.
}
}

Categories

Resources