Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a C# Multithreaded Application use separate WorkingDirectories per thread?

In C# (.NET), can two threads running in the same application have DIFFERENT "WorkingFolders"??

As best I can tell, the answer would be "NO". I think the WORKING DIR is set by the PROCESS in Win32.. Am I wrong here?

According to the following test code, (as well the Win32 SetCurrentDirectory API call), this is NOT possible, but has anyone figured out a way to MAKE it possible?

using System;
using System.Threading;

public class TestClass {

  public  ManualResetEvent _ThreadDone = new ManualResetEvent(false);

  public static void Main() {
    Console.WriteLine(Environment.CurrentDirectory);

    Thread _Thread = new Thread(new ParameterizedThreadStart(Go));
    TestClass test = new TestClass();

    _Thread.Start(test);
    if(test._ThreadDone.WaitOne()) {
      Console.WriteLine("Thread done.  Checking Working Dir...");
      Console.WriteLine(Environment.CurrentDirectory);
    }
  }

  public static void Go(object instance) {
    TestClass m_Test = instance as TestClass;
    Console.WriteLine(Environment.CurrentDirectory);
    System.IO.Directory.SetCurrentDirectory("L:\\Projects\\");
    Console.WriteLine(Environment.CurrentDirectory);
    m_Test._ThreadDone.Set();
  }
}

I know SOMEONE out there has to have ran across this before!

like image 452
LarryF Avatar asked Jun 13 '13 22:06

LarryF


1 Answers

I'm going to guess what you're trying to do is to make code such as File.Open("Foo.txt") behave differently on different threads. Can you do this? The short answer is No - nor should you be trying to do this. On Windows, the current working directory is set at the process level. The .NET framework does not violate that rule.

A better approach would be to create an abstraction on top of Environment.CurrentDirectory that is thread specific. Something like:

public static class ThreadEnvironment
{
   [ThreadStatic]
   static string _currentDir;

   public static string CurrentDirectory
   {
      get
      {
         if (_currentDir == null) // If Current Directory has not been set on this thread yet, set it to the process default
         {
            _currentDir = Environment.CurrentDirectory;
         }

         return _currentDir;
      }

      set
      {
         if (value == null)
            throw new ArgumentException("Cannot set Current Directory to null.");

         _currentDir = value;
      }
   }
}

You can then refer to ThreadEnvironment.CurrentDirectory to get that thread's current directory, which will default to the process directory if it has not been set on that thread. For example:

static void Main(string[] args)
{
   (new Thread(Thread1)).Start();
   (new Thread(Thread2)).Start();
}

static void Thread1()
{
   Console.WriteLine("Thread1 Working Dir is: {0}", ThreadEnvironment.CurrentDirectory);
   ThreadEnvironment.CurrentDirectory = @"C:\";
   Console.WriteLine("Thread1 Working Dir is: {0}", ThreadEnvironment.CurrentDirectory);
}

static void Thread2()
{
   Console.WriteLine("Thread2 Working Dir is: {0}", ThreadEnvironment.CurrentDirectory);
   ThreadEnvironment.CurrentDirectory = @"C:\Windows";
   Console.WriteLine("Thread2 Working Dir is: {0}", ThreadEnvironment.CurrentDirectory);
}

You would, of course, then need to qualify that path whenever dealing with file IO, however this is arguably a safer design anyway.

like image 83
Mike Christensen Avatar answered Nov 05 '22 20:11

Mike Christensen