You can add a reference to System.Configuration
in your project and then:
using System.Configuration;
then
string sValue = ConfigurationManager.AppSettings["BatchFile"];
with an app.config
file like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="BatchFile" value="blah.bat" />
</appSettings>
</configuration>
- Is there a clearer definition of a "zombie thread" than what I've explained here?
Seems like a pretty good explanation to me - a thread that has terminated (and can therefore no longer release any resources), but whose resources (e.g. handles) are still around and (potentially) causing problems.
- Can zombie threads occur on .NET? (Why/Why not?)
- If applicable, How could I force the creation of a zombie thread in .NET?
They sure do, look, I made one!
[DllImport("kernel32.dll")]
private static extern void ExitThread(uint dwExitCode);
static void Main(string[] args)
{
new Thread(Target).Start();
Console.ReadLine();
}
private static void Target()
{
using (var file = File.Open("test.txt", FileMode.OpenOrCreate))
{
ExitThread(0);
}
}
This program starts a thread Target
which opens a file and then immediately kills itself using ExitThread
. The resulting zombie thread will never release the handle to the "test.txt" file and so the file will remain open until the program terminates (you can check with process explorer or similar). The handle to "test.txt" won't be released until GC.Collect
is called - it turns out it is even more difficult than I thought to create a zombie thread that leaks handles)
- If applicable, How can I leverage locking without risking a zombie thread scenario in .NET?
Don't do what I just did!
As long as your code cleans up after itself correctly (use Safe Handles or equivalent classes if working with unmanaged resources), and as long as you don't go out of your way to kill threads in weird and wonderful ways (safest way is just to never kill threads - let them terminate themselves normally, or through exceptions if necessary), the only way that you are going to have something resembling a zombie thread is if something has gone very wrong (e.g. something goes wrong in the CLR).
In fact its actually surprisingly difficult to create a zombie thread (I had to P/Invoke into a function that esentially tells you in the documentation not to call it outside of C). For example the following (awful) code actually doesn't create a zombie thread.
static void Main(string[] args)
{
var thread = new Thread(Target);
thread.Start();
// Ugh, never call Abort...
thread.Abort();
Console.ReadLine();
}
private static void Target()
{
// Ouch, open file which isn't closed...
var file = File.Open("test.txt", FileMode.OpenOrCreate);
while (true)
{
Thread.Sleep(1);
}
GC.KeepAlive(file);
}
Despite making some pretty awful mistakes, the handle to "test.txt" is still closed as soon as Abort
is called (as part of the finalizer for file
which under the covers uses SafeFileHandle to wrap its file handle)
The locking example in C.Evenhuis answer is probably the easiest way to fail to release a resource (a lock in this case) when a thread is terminated in a non-weird way, but thats easily fixed by either using a lock
statement instead, or putting the release in a finally
block.
See also
Best Solution
I think you can do this by setting the TreeView control's DrawMode to OwnerDrawText, and perform the drawing inside a
DrawNode
event handler.Sample of DrawNode implementation (split the node string at space, draw the first element in bold, the rest of the string using regular font and if there is no space, we let the OS do the drawing instead):
Note: you may want to add a variable or property to the form that holds the bold font instead of recreating and disposing it for each TreeNode that is drawn.