Reputation:
I just barely started programming in C# and I am running into a small issue with background threads running infinite while loops inside of them.
A little background: I am trying to make a physical notification light for Outlook. Right now I am making it in a WPF Application to just test it before I throw it in an Outlook Add-in.
I have a button that opens up a new background thread and runs a new instance of this class:
public class LightControl
{
private byte light;
public byte Light
{
get { return light; }
set { light = value; }
}
private string color;
public string Color
{
get { return color; }
set { color = value; }
}
private int delay;
public int Delay
{
get { return delay; }
set { delay = value; }
}
private bool status;
public bool Status
{
get { return status; }
set { status = value; }
}
public void notification()
{
Action<byte, string, int, bool> lightNot =
delegate(byte i, string c, int d, bool s)
{ lightLoop(i, c, d, s); };
lightNot(light, color, delay, status);
}
private void lightLoop(byte index, string color, int delay, bool state)
{
BlinkStick device = BlinkStick.FindFirst();
if (device != null && device.OpenDevice())
{
while (state)
{
device.SetColor(0, index, color);
Thread.Sleep(delay);
device.SetColor(0, index, "black");
Thread.Sleep(delay);
}
}
}
}
I have another button that feeds a false into the status member of this class which should trickle down to the private method lightLoop and kill that infinite loop. Killing the entire thread in the process.
It isn't doing that though. The loop continues to run. What could be the cause of that?
Any help on this will be greatly appreciated.
Here is how I start the thread:
private void lightStart(byte index)
{
Random random = new Random();
int randNumber = random.Next(0, 5);
LightControl light = new LightControl();
light.Light = index;
light.Color = colors[randNumber]; //random color generator just for fun.
light.Delay = 500;
light.Status = status; //global bool on the MainWindow Class
Thread lightThread = new Thread(new ThreadStart(light.notification));
lightThread.IsBackground = true;
lightThread.Start();
}
I apologize in advance for any inaccuracy in terminology still wrapping my head around all of this.
Upvotes: 2
Views: 552
Reputation: 5953
Another option is using ref
to achieve what you want. Essentially, it allows you to pass a reference to your bool
instead of the actual value at the time of evaluation. This allows changes to the value to affect the method it was passed to, even if it is a value type.
Here's a basic example, you can take the concepts from this and apply them for your situation.
static bool state = true;
public static void _Main(string[] args)
{
Console.WriteLine("1. Main thread: {0}", DateTime.Now.ToString("HH:mm:ss.fffffff"));
Thread t = new Thread(new ThreadStart(StartLoop));
t.Start();
Console.WriteLine("2. Main thread: {0}", DateTime.Now.ToString("HH:mm:ss.fffffff"));
Thread.Sleep(5000);
state = false;
Console.WriteLine("3. Main thread: {0}", DateTime.Now.ToString("HH:mm:ss.fffffff"));
}
delegate void MyDelegate(ref bool s);
public static void StartLoop()
{
MyDelegate myDelegate = LoopMethod;
myDelegate(ref state);
}
public static void LoopMethod(ref bool state)
{
while (state)
{
Console.WriteLine("LoopMethod running: {0}", DateTime.Now.ToString("HH:mm:ss.fffffff"));
Thread.Sleep(1000);
}
}
Output:
1. Main thread: 20:00:28.3693277
2. Main thread: 20:00:28.3753284
LoopMethod running: 20:00:28.3793309
LoopMethod running: 20:00:29.3813856
LoopMethod running: 20:00:30.3816387
LoopMethod running: 20:00:31.3818790
LoopMethod running: 20:00:32.3829344
3. Main thread: 20:00:33.3760889
Nothing else is printed.
This also requires changing your delegate
from an anonymous delegate
to a strongly-typed delegate
.
Upvotes: 2
Reputation: 709
As stated in @JohnKoerner's comment, booleans are value types, so if you pass a parameter and change the value outside of the method it will never be reflected inside it.
To solve it, encapsulate it inside an object and receive the object as parameter.
Parameter
public class State
{
public Boolean IsActive {get;set;}
}
Your loop
while (state.IsActive)
{
//do the job
}
This way when you update the IsActive property the method will know.
Upvotes: 2