问题 C#多线程应用程序是否可以为每个线程使用单独的WorkingDirectories?


在C#(.NET)中,在同一个应用程序中运行的两个线程可以有不同的“WorkingFolders”吗?

我可以说,最好的答案是“不”。我认为WORKING DIR是由Win32中的PROCESS设置的。我在这里错了吗?

根据以下测试代码,(以及Win32 SetCurrentDirectory API调用),这是不可能的,但有没有人找到一种方法来实现它?

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

我知道有人在那之前必须遇到过这个问题!


866
2018-06-13 22:32


起源

尝试这个的目的是什么?通常最好只设计代码以允许您传入适当的文件夹... - Reed Copsey
可能是通过为每个线程创建一个单独的应用程序域。我已将此添加为评论,因为我目前无法展示示例。 - MarcF
@MarcF应用程序域不会更改每个进程(FYI)的一个环境集。 - Erik Philips
@ErikPhilips - 我的猜测是在任何其他答案之前发布的。我高兴地站起来纠正。 - MarcF
它是一个不是[ThreadStatic]的全局变量。所以当然有可能。您也不需要线程,许多程序已从OpenFileDialog中删除,其RestoreDirectory属性设置为默认值。 - Hans Passant


答案:


我猜猜你是什么  要做的就是制作代码 File.Open("Foo.txt") 在不同的线程上表现不同。你能做这个吗?简短的回答是 没有  - 你也不应该  去做这个。在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时,您需要限定该路径,但无论如何,这可以说是更安全的设计。


9
2018-06-13 22:37



如何创造不同的 AppDomains和设置 AppDomainSetup.PrivateBinPath 那里?这样他就能以某种方式“设定”它。也许我弄错了 - Odys
我认为这里的目标是制作 File.Open("Foo.txt") 在不同的线程上表现不同。答案是否定的,你不能这样做也不应该试图这样做。 - Mike Christensen


有没有人想出办法让它成为可能?

这很简单 不可能。每个App Domain甚至不能有不同的工作目录。

Windows规则是:每个进程一个环境集。在.NET中运行不会更改基本规则。

如果您在加载程序集时遇到问题,请考虑将相应的文件夹添加到PATH环境变量中。


3
2018-06-13 22:36



谢谢Erik,这是我所怀疑的,但我想到目前为止,我认为Mike Christensen有最好的答案......这允许我将CurrentDir + Passed Path / File硬编码到我的IO功能并允许我的活动我正在寻找。但是,由于Win32文档,我担心情况如此...... - LarryF