Thread.ResetAbort leaving the thread in a broken state

T

Tum

Hi,

I've been working on DotGNU trying to implement the correct semantics for
monitors, thread.abort (etc) in the runtime.

Russell Stuart posted an example a few days ago which we discovered would
let two locked blocks to execute simulatenously.

As I moved onto implemeting Abort, I wondered how Thread.Abort() could
possibly abort a thread but yet maintain monitor consistancy. For example,
if a thread is aborted while it is waiting on a monitor and calls
ResetAbort, the thread will reenter a synchronized block. It wouldn't make
sense for the aborted thread to own the monitor because it never got pulsed
or released by the thread that really owns the monitor. Naturally, if the
aborted thread doesn't own the monitor then it can't call Monitor.Exit on
the monitor right? I was suprised to find out that the aborted thread could
call Monitor.Exit on the monitor -- even though it didn't own it. My first
thought was that the runtime allowed the abort thread to have a "pretend"
count on the monitor so that it could call Monitor.Exit on the monitor the
appropriate amount of times it needed as the ThreadAbortException got
propagated upwards. After a bit of testing it turns out that if a thread is
aborted the runtime simply ignores calls to Monitor.Exit and even worse, it
continues to ignore calls to Monitor.Exit even after you call
Thread.ResetAbort.

Here's some example code:

using System;

using System.Threading;

public class Test2

{

Thread thread1, thread2;


public void Run1()

{

Thread.Sleep(2000);


lock (this)

{

Monitor.Pulse(this);

thread2.Abort();

}

Console.WriteLine("1 Released Lock");

}


public void Run2()

{

lock(this)

{

try

{

Monitor.Wait(this);

}

catch (ThreadAbortException)

{

Thread.ResetAbort();

}


Monitor.Exit(this);

Monitor.Exit(typeof(string));

Monitor.Exit(typeof(string));

Monitor.Exit(this);

Monitor.Exit(this);

Monitor.Exit(this);

}

}

public void Go()

{

thread1 = new Thread(new ThreadStart(Run1));

thread2 = new Thread(new ThreadStart(Run2));


thread1.Start();

thread2.Start();

}


public static void Main()

{

new Test2().Go();

}

}





It should throw SynchronizationLockExceptions but doesn't. In fact, it'll
happily let you call Monitor.Exit as many times as you like on *ANY* objects
you like. EWWWWW.

Hands up anyone who thinks Thread.Abort is a bad idea.

^Tum
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top