Может ли С# многопоточное приложение использовать seprate WorkingDirectories для потока?

В С# (.NET), два потока, запущенные в одном приложении, имеют РАЗЛИЧНЫЕ "Рабочие папки"

Насколько я могу судить, ответ будет "НЕТ". Я думаю, что WORKING DIR установлен PROCESS в Win32.. Я здесь не прав?

Согласно следующему тестовому коду (а также вызов API Win32 SetCurrentDirectory), это НЕ возможно, но кто-нибудь понял способ сделать это возможным?

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();
  }
}

Я знаю, что кто-то там должен был наткнуться на это раньше!

Ответ 1

Я собираюсь угадать, что вы пытаетесь сделать, чтобы сделать код, такой как File.Open("Foo.txt"), вести себя по-разному в разных потоках. Ты можешь сделать это? Короткий ответ: No - и вы не должны пытаться это сделать. В Windows текущий рабочий каталог установлен на уровне процесса. Рамка .NET не нарушает это правило.

Лучшим подходом было бы создать абстракцию поверх Environment.CurrentDirectory, которая является специфичной для потока. Что-то вроде:

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;
      }
   }
}

Затем вы можете обратиться к ThreadEnvironment.CurrentDirectory, чтобы получить текущий каталог этого потока, который будет по умолчанию для каталога процессов, если он не был установлен в этом потоке. Например:

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);
}

Вы, конечно, должны были бы квалифицировать этот путь при работе с файловым IO, однако это, возможно, более безопасный дизайн.

Ответ 2

Кто-нибудь понял способ сделать это возможным?

Это просто невозможно. У вас даже не может быть разных рабочих каталогов для домена приложений.

Правило Windows: одно окружение для каждого процесса. Запуск в .NET не изменит основные правила.

Вместо этого, если у вас возникла проблема с загрузкой сборок, рассмотрите возможность добавления соответствующей папки в переменную среды PATH.