How to abort a thread properly? [duplicate] - c#

This question already has answers here:
How to terminate a thread in C#?
(4 answers)
Closed 5 years ago.
I'm writing a scripting interface for a server emulator for NPC chats. The player can initiate a NPC chat by clicking on the NPC. The NPC can send text dialogs. Those text dialogs also contain a End Chat button to end the chat before the script finishes execution, or the player can continue with the text dialogs normally until they end.
When the player interrupts the chat, a special packet is sent.
I've created a class called WaitableResult which takes advantage of ManualResetEvent to block the current thread until given result and then returns the result:
public sealed class WaitableResult<T> where T : struct
{
public T Value { get; private set; }
private ManualResetEvent mEvent;
public WaitableResult()
{
mEvent = new ManualResetEvent(false);
}
public void Wait()
{
mEvent.WaitOne();
}
public void Set(T value)
{
mEvent.Set();
this.Value = value;
}
}
This is my script classes:
internal sealed class NpcScript : ScriptBase
{
public WaitableResult<bool> BoolResult { get; private set; }
private Npc mNpc;
private Player mPlayer;
public NpcScript(Npc npc, Player player)
: base(string.Format(#"..\..\scripts\npcs\{0}.lua", npc.Script), true)
{
mNpc = npc;
mPlayer = player;
mPlayer.NpcConversation = this;
this.Expose("answer_no", false);
this.Expose("answer_yes", true);
this.Expose("answer_decline", false);
this.Expose("answer_accept", true);
this.Expose("say", new Func<string, bool>(this.Say));
this.Expose("askYesNo", new Func<string, bool>(this.AskYesNo));
}
public override void Dispose()
{
base.Dispose();
mPlayer.NpcConversation = null;
}
private bool Say(string text)
{
this.BoolResult = new WaitableResult<bool>();
using (OutPacket outPacket = mNpc.GetDialogPacket(ENpcDialogType.Standard, text, 0, 0))
{
mPlayer.Client.SendPacket(outPacket);
}
this.BoolResult.Wait();
return this.BoolResult.Value;
}
private bool AskYesNo(string text)
{
this.BoolResult = new WaitableResult<bool>();
using (OutPacket outPacket = mNpc.GetDialogPacket(ENpcDialogType.YesNo, text))
{
mPlayer.Client.SendPacket(outPacket);
}
this.BoolResult.Wait();
return this.BoolResult.Value;
}
}
public abstract class ScriptBase
{
private string mPath;
private Thread mThread;
private MoonSharp.Interpreter.Script mScript;
public ScriptBase(string path, bool useThread = false, CoreModules modules = CoreModules.None)
{
mPath = path;
if (useThread) mThread = new Thread(new ThreadStart(() => mScript.DoFile(mPath)));
mScript = new MoonSharp.Interpreter.Script(modules);
}
public void Execute()
{
if (mThread != null)
{
mThread.Start();
}
else
{
mScript.DoFile(mPath);
}
}
public virtual void Dispose()
{
if (mThread != null)
{
mThread.Abort();
mThread = null;
}
}
protected void Expose(string key, object value)
{
mScript.Globals[key] = value;
}
}
And here's an example of a script:
say('test')
say('some more stuff')
say('good bye')
When a player initiates a chat with a NPC and finishes it without interrupting it (aka closing it using the End Chat button), the thread should be aborted by itself (as it finished all it's instructions).
However, when a player aborts the chat before it finishes execution, I'm calling the Dispose button to manually abort the thread - but I'm not sure it's the right way to do it.
My memory usage also increases by 1 MB everytime a player starts a chat, so that's also kind of weird.

As Quantic has already addressed, aborting a thread by means of Thread.Abort invites unexpected - even dangerous results. Quantic also addressed the preferred pattern to deal with a thread, usually the thread loops and checks for a termination flag, which is not possible if you are executing an arbitrary Lua script.
One option you have is to create a minimalistic debugger and attach it to your script. Once this debugger is attached, the IDebugger.GetAction() method will be called for every instruction in the running script. If during the GetAction()call you raise an Exception, the script will be terminated, cleanly, by the debugger.
Here is an example of a sentinel, minimalistic debugger that stops a long-running script using such a technique. As you can see, most of the implementation is empty. In your case, instead of using a running instruction counter, you may simply have a boolean flag that indicates that the script must be terminated.
public DebuggerAction GetAction(int ip, SourceRef sourceref)
{
if( _abortScript )
throw new MyException(); // abort cleanly
// Proceed running the next statement
return new DebuggerAction() {
Action = DebuggerAction.ActionType.StepIn,
};
}
Regarding the memory increase you are experiencing, that is one of the inconveniences of manually spawning threads, each thread initializes its own stack space and on a 32-bit process, the default is precisely 1MB. There is a Thread constructor overload that allows you to customize the stack size; Depending on the complexity of the scripts, this value could probably be set to a smaller value without risking a stack overflow condition. Another option to minimize memory usage would be to use a Task.Run instead of spawning your own thread (this makes use of the Thread pool), but then refraining from using Thread.Abort would be mandatory, you don't want to go killing pooled threads!

Related

C# Set Variable in Thread

I'm trying to work with Threads for a private Project and I have a question which is, as I think very easy to answer.
Is it possible to set a variable in another thread?
Here a little Code example to show you what I'm trying to do:
public class PartyClass
{
public boolean partytime = true;
public void MakeParty()
{
while(partytime)
Console.WriteLine("I'm making a party here");
Console.WriteLine("The party ended. Please leave now");
}
public void StopParty()
{
partytime = false;
}
}
public class MainThread
{
public static int Main(String[] args)
{
PartyClass party = new PartyClass();
Thread partyThread = new Thread(new ThreadStart(party.MakeParty()));
partyThread.Start();
while (!partyThread.IsAlive) ;
System.Threading.Thread.Sleep(5000);
// Now I want to somehow call the StopParty() Method
}
}
I don't know if it's really stupid what I'm trying to do but I think its a nice way to stop the "Partythread" in a clean way.
Is this possible or is there a better solution for this?
Thanks for your Ideas.
(I didn't test the Code - just wrote it out of my head)
You call the stop method just the way you called the start method:
party.StopParty();
In order to ensure that the changes made in another thread aren't just cached, the partytime field should be marked as volatile as well.
You should use synchronization facilities, such as CancellationToken.
Your code will look like:
public class PartyClass
{
private readonly CancellationToken _cancellationToken;
public PartyClass(CancellationToken cancellationToken)
{
_cancellationToken = cancellationToken;
}
public void MakeParty()
{
while (!_cancellationToken.IsCancellationRequested)
Console.WriteLine("I'm making a party here");
Console.WriteLine("The party ended. Please leave now");
}
}
public class MainThread
{
public static int Main(String[] args)
{
var cancellationSource = new CancellationTokenSource();
PartyClass party = new PartyClass(cancellationSource.Token);
Thread partyThread = new Thread(party.MakeParty);
partyThread.Start();
System.Threading.Thread.Sleep(5000);
cancellationSource.Cancel();
partyThread.Join();
}
}
It is thread-safe and suitable not only for this, but also for more advanced scenarios, as well as for working with tasks.
If want more threads to ask for the same variable, take care about thread syncrhonization issues (when two threads try to access the same variable).
Im going to show the safest way (might be more than what you need). The best to way to do it is declaring an static object to set a lock in order to make sure you have one thread changing the party flag at once.
public class PartyClass
{
private object _partyTimeLock = new Object(); // executed at class init
private boolean partyTime= true;
public bool IsPartyGoingOn()
{
bool itIsGoingOn = false;
lock(_partyTimeLock) {
itIsGoingOn = partyTime;
}
return itIsGoingOn;
}
public void StopParty()
{
lock(_partyTimeLock) {
partyTime = false;
}
}
public void MakeParty()
{
while(IsPartyGoingOn()) {
Console.WriteLine("I'm making a party here");
}
Console.WriteLine("The party ended. Please leave now");
}
}
In this example here, no matter who try to call the IsPartyGoingOn(), you will never have an issue (no matter if it the class own thread or another one). The lock keyword will guarantee you are doing the right way.

C# thread accesed to if block, whose condition returns false

This block of code is being accessed by many threads
// All code is from same class
public void ExecuteCommand(IAsciiCommand command, IAsciiCommandSynchronousResponder responder)
{
lock (commander)
{
if (commander.IsConnected)
{
commander.ExecuteCommand(command, responder);
}
}
}
public void Disconnect()
{
var tmp = commander.IsConnected;
commander.Disconnect();
if (commander.IsConnected != tmp && !commander.IsConnected)
{
OnPropertyChanged("IsConnected");
}
}
And eventually i get this:
How is this possible, that thread accessed into if statement, whose condition returns false? How can i fix it?
This is happening because the check and the call lack atomicity. Here is a sequence of events that could lead to an exception:
Two threads, A and B, are reaching the condition at the same time
Thread A checks the condition, which returns true, so it enters the if block
At the same time, thread scheduler decides that thread A has exhausted its time slot, and suspends it
Thread B calls Disconnect
Thread scheduler resumes thread A, which is inside the if condition. However, the command is no longer connected
This causes the exception
You can fix it by locking commander inside Disconnect().
public void Disconnect()
{
bool doEvent;
lock(commander) {
var tmp = commander.IsConnected;
commander.Disconnect();
doEvent = (commander.IsConnected != tmp && !commander.IsConnected)
}
// Run OnPropertyChanged outside the locked context
if (doEvent)
{
OnPropertyChanged("IsConnected");
}
}
You need to lock on a static object. Right now you're creating separate locks based on the object your are working with (commander). Try this:
public class WhatEverClassHasTheExecuteCommandMethod
{
private static object _lock = new object();
public void ExecuteCommand(IAsciiCommand command, IAsciiCommandSynchronousResponder responder)
{
lock (_lock)
if (commander.IsConnected)
commander.ExecuteCommand(command, responder);
}
}
If you are not locking while disconnecting, it's entirely possible to get a race condition. The basic solution is to add a lock inside the Disconnect method:
public void Disconnect()
{
lock (commander)
{
var tmp = commander.IsConnected;
commander.Disconnect();
if (commander.IsConnected != tmp && !commander.IsConnected)
OnPropertyChanged("IsConnected");
}
}

Synchronising access to state variable which is reset by a timer

I am currently working on a project in C#. I am syncing access to a state variable using a single lock. This state variable is triggered to be set for a given period of time and then should have its value reset. My current code is as follows.
using System.Threading;
class Test
{
object syncObj = new object();
bool state = false;
Timer stateTimer;
Test()
{
stateTimer = new Timer(ResetState, this, Timeout.Infinite, Timeout.Infinite);
}
void SetState()
{
lock(syncObj)
{
state = true;
stateTimer.Change(1000, Timeout.Infinite);
}
}
static void ResetState(object o)
{
Test t = o as Test;
lock(t.syncObj)
{
t.state = false;
}
}
}
Given that it is valid to call SetState again before ResetState is called by the Timer (i.e. it is allowed to extend the period of time that state is true), I can imagine situations where a single lock may not be enough. The specific case I'm thinking of is this
Both SetState and ResetState are entered at the same time, on the main thread and the Timer thread respectively
SetState acquires the lock first and correctly sets state to true and triggers the timer to start again
ResetState then incorrectly sets state to false meaning that state is not true for the expected period of time
I've been scratching my head over this one for a little while. The closest I got to being able to solve it was by using two locks but in the end I found this caused other issues (at least, the way I'd done it).
Is there a known way to solve this problem (and should I be reading something to refresh my knowledge of synchronisation)?
UPDATE: I forgot to mention that the current state of the timer cannot be queried in this instance. If it could I would imagine checking the remaining time in ResetState to determine that the timer is really stopped.
First and foremost: it's a bad idea to expose the locking object publicly!
class Test
{
private object syncObj = new object();
private bool state = false;
private Timer stateTimer;
public Test()
{
stateTimer = new Timer(ResetState, this, Timeout.Infinite, Timeout.Infinite);
}
public void SetState()
{
lock(syncObj)
{
state = true;
stateTimer.Change(1000, Timeout.Infinite);
}
}
public static void ResetState(object o)
{
Test t = o as Test;
t.ResetState();
}
Since you're no longer exposing the locking object, you'll have to create another method to reset the state:
public void ResetState()
{
lock(syncObj)
{
state = false;
stateTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
}
Note that we also take care of another problem in the new ResetState method and that is to force the timer not to fire again. This will only guarantee that the state flag will not be in out of sync with the timer; i.e. if you set the state, it will remain set for the expected amount of time or until the reset method is called.
Update
If you want to reject the reset attempt, then make the state variable an enum:
enum EState
{
Off = 0,
On = 1,
Waiting = 2
}
private EState state = EState.Off;
// Provide a state property to check if the state is on or of (waiting is considered to be Off)
public bool State{ get{ return state == EState.On;} }
In addition, you will now need to modify the SetState method and you will need two reset methods (the private one will be used with by the timer).
public void SetState()
{
lock(syncObj)
{
state = EState.Waiting;
stateTimer.Change(1000, Timeout.Infinite);
}
}
public void ResetState()
{
lock(syncObj)
{
if(state != EState.Waiting)
{
state = EState.Off;
}
}
}
private void TimerResetState()
{
lock(syncObj)
{
state = EState.Off;
stateTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
So now your constructor will look like this:
public Test()
{
stateTimer = new Timer(TimerResetState, this, Timeout.Infinite, Timeout.Infinite);
}
Things should work roughly along those lines.

Using a thread to continuously check for changes to a value

I am trying to create a thread which will continuously check for changes to a value, then visually show that change in a PictureBox located in my GUI.
What I actually wrote is a bit more complicated, so I simplified it while keeping the basic idea, I would be happy to provide clarification if this isn't enough:
public class CheckPictures
{
PictureBox update;
List<String> check;
public CheckPictures(PictureBox anUpdate, List<String> aCheck)
{
update = anUpdate;
check = aCheck;
}
public void start()
{
while(true)
{
if (aCheck[0] == "Me")
{
update.Image = Image.fromFile("");
}
}
}
}
static int Main(string[] args)
{
List<String> picturesList = new List<String>();
CheckPictures thread1 = new CheckPictures(PictureBox1, picturesList);
Thread oThread1 = new Thread(thread1.start));
}
What I want it to do is dynamically change the picture in PictureBox1 if I were to add the string "Me" to pictureList. The above code isn't working like I'd hoped. I had thought that by passing the actual PictureBox and List, any changes to the List elsewhere is the program would be caught by the thread. So my first question is: Is this possible? And if so, what change would I need to make to my code to achieve it?
You might want to use events. You register an eventhandler and when something changes in one thread it calls an event handler in the other to do the work. Busy waiting wastes cpu.
You definetely do not want to do an infinite loop, this will just consume cpu:
while(true)
{
if (aCheck[0] == "Me")
{
update.Image = Image.fromFile("");
}
}
I think you should look into the CountdownLatch class.
public class CountdownLatch
{
private int m_remain;
private EventWaitHandle m_event;
public CountdownLatch(int count)
{
m_remain = count;
m_event = new ManualResetEvent(false);
}
public void Signal()
{
// The last thread to signal also sets the event.
if (Interlocked.Decrement(ref m_remain) == 0)
m_event.Set();
}
public void Wait()
{
m_event.WaitOne();
}
}
The basic idea here is that you need to stop execution on your thread for some time and resume whenever a certain condition has been met (perhaps on another thread).
In other words, you will have a counter, decrement its value on certain condition and whenever it goes to zero you fire your event, execute some code and then start over (stop execution and wait for the counter to go to zero).
In your case you could set the counter to 1 and decrement its value whenever you've set aCheck[0] = "Me"; This way you don't waste CPU.
Pseudo code:
Initialize counter:
CountdownLatch latch = new CountdownLatch(1);
Make thread wait:
public void start()
{
while(true)
{
latch.Wait(); //execution stops
{
//execution resumes once the latch counter is zero.
if (aCheck[0] == "Me") //double check you have what you need
{
update.Image = Image.fromFile("");
latch = new CountdownLatch(1); //reset if you need to do it again
}
}
}
}
Whenever your condition is met (i.e. aCheck[0] = "Me";) signal your latch:
latch.Signal();
this last line will make the thread resume execution. Good stuff.
Create some object, which will raise event, when new picture was added. E.g. class representing pictures collection:
public class PicturesCollection
{
public event EventHandler<PictureAddedEventArgs> PictureAdded;
private List<string> _pictures = new List<string>();
public void Add(string name)
{
_pictures.Add(name);
if (PictureAdded != null)
PictureAdded(this, new PictureAddedEventArgs(name));
}
public IEnumerable<string> Pictures
{
get { return _pictures; }
}
}
If you want to provide some additional data to event, create custom EventArgs:
public class PictureAddedEventArgs : EventArgs
{
public PictureAddedEventArgs(string name)
{
Name = name;
}
public string Name { get; private set; }
}
All you need now - create pictures collection and subscribe to that event:
static int Main(string[] args)
{
PicturesCollection pictures = new PicturesCollection();
pictures.PictureAdded += Pictures_PictureAdded;
}
static void Pictures_PictureAdded(object sender, PictureAddedEventArgs e)
{
if (e.Name == "Me")
PictureBox1.Image = Image.fromFile("");
}
If you add somewhere in your application new picture to collection, it will raise PictureAdded event, which you can handle and update PictureBox. CPU is not wasted in this case.

Threaded function does not behave as I expect it to

This is (roughly) what I have:
class A
{
public bool IsInUpdate = false;
public void Update()
{
IsInUpdate = true;
//(...do stuff...)
IsInUpdate = false;
}
}
class B
{
A a_inst;
System.Threading.Thread physicsThread = null;
void Draw()
{
physicsThread = new System.Threading.Thread(a_inst.Update);
physicsThread.Start();
}
void Update()
{
while(physicsThread.IsAlive)
{
// Right here there can be cases where physicsThread.IsAlive is true but IsInUpdate is false, how does that happen?
}
(...do stuff...)
}
}
Question is in the comments of the code. Basically the physics thread instance says it's alive but the function it's calling has clearly been finished calling (as can be seen by the bool being set to false).
Any ideas why this happens? All I want to do is make sure the update function in class B does not execute until the threaded update function of class A has executed...
Since IsInUpdate is simply a public field (and non-volatile at that), there are no guarantees about what you see; the normal sensible rules about what you see only apply on a single thread, and you have not guarded any of this data. There is also an edge-case around the start condition, but personally I would be using either lock (if you need to wait for it to complete), or maybe Interlocked if you just need to know if it is active.
For example:
class A
{
private readonly object syncLock = new object();
public object SyncLock { get { return syncLock; } }
public void Update()
{
lock(SyncLock)
{
//(...do stuff...)
}
}
}
and
void Update()
{
lock(a_inst.SyncLock)
{
(...do stuff...)
}
}
With the above, you are guaranteed that only one thread will have the lock at any time, so if you get to "do stuff" you know that it isn't also running the other Update(). If you need to wait etc there are also Wait() / Pulse() methods against locks, or you can use gates such as ManualResetEvent/AutoResetEvent.
Things like lock also ensure correct memory barriers between the threads, so you see the correct data.
This situation can happen when the Update function has not been called yet. Just because you have called Start on the thread doesn't mean it's immediately going to execute it's main function. I'm not 100% sure if there is a slight window of opportunity where the thread is still alive but the main function has finished executing.
Basically you want to have a look at ManualResetEvent or AutoResetEvent to signal that your thread has finished working. Alternatively an event you can raise after Update() has finished and B can subscribe to might be good enough. Like this:
class A
{
public event EventHandler UpdateFinished;
public void Update()
{
... do work
var handler = UpdateFinished;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
class B
{
public void Draw()
{
a_inst.UpdateFinished += HandleUpdateFinished;
... start your thread
}
private void HandleUpdateFinished(object sender, EventArgs e)
{
... do whatever
}
}

Categories