大家好,我想实现这样的一个需求:
随机生成一个目录名称,如果这个目录不存在,那么就创建,如果存在,就重新生成,直到目录不存在并生成为止,但是运行这段代码的线程可能有成千上万个,所以需要加锁,并且效率要尽可能高。
我是这样想的:判断目录是否存在、创建新的目录,这应该是一个原子操作。但是如果两个线程生成的不是同一个路径,那么它们就不应该互斥,只有在生成的目录名称完全相同时,才需要互斥。
例如:
线程1生成的path="C:\folder1"
线程2生成的path="C:\folder1"
由于线程1和线程2生成的路径相同,所以应该进行互斥操作,避免出错。
但是如果:
线程1生成的path="C:\folder1"
线程2生成的path="C:\folder2"
由于线程1和线程2生成的路径不相同,所以不需要进行互斥操作。
不知道如何实现该需求?或者应该使用哪个锁?
谢谢大家。

解决方案 »

  1.   

    private object thisLock = new object(); public void YourThreading() {
    string temppath;
    //ToDo Something
    lock (thisLock) {
    if (Directory.Exists(temppath)) {
    Directory.CreateDirectory(temppath);
    }else{
    //ToDo Something
    }
    }
    }
      

  2.   

    thisLock应该是静态的吧?如果不是静态的,那么几个线程中的thisLock可能不是同一个对象。
    谢谢。
      

  3.   

    线程安全
    此类型的任何公共 static(在 Visual Basic 中为 Shared) 成员都是线程安全的。但不保证所有实例成员都是线程安全的。http://msdn.microsoft.com/zh-cn/library/vstudio/system.io.directory%28v=vs.90%29.aspx
      

  4.   

    我这里的逻辑基本上是这样的:Object thisLock = new Object();
    private void TryCreateFolder()
    {
        while (true) // 循环:直到创建目录成功之后才退出循环
        {
            // 生成路径
            string path = GeneratePath();
            lock(thisLock) // 加锁
            {
                // 如果目录已经存在,那么生成另一个路径
                if (Directory.Exists(path)) 
                {
                    continue;
                }
                else // 目录不存在,那么创建之后,退出
                {
                    Directory.CreateDirectory(path);
                    return;
                }
            }
        }
    }由于生成目录算法GeneratePath()可以保证在99.99%的可能下,path是各不相同的,因此这里对所有的线程都加锁是不科学的。
    我的想法是这样的,假设线程1生成了路径:"C:\folder1",而且运行到了lock{}里面,
    如果线程2生成的路径也是"C:\folder1",那么线程2必须等待线程1运行完lock{}之后才能够执行lock{}代码。
    如果线程2生成的路径和线程1生成的路径不一样,例如"C:\folder2",那么虽然线程1还没有执行完lock{}代码,线程2也可以执行lock{}里面的代码。
      

  5.   

    如果只有Directory.CreateDirectory这一个I/O操作,那么是没必要
    但如果某线程在Directory.Exists时返回了false,另一个线程却在之后立即创建了同名文件夹呢?Directory.CreateDirectory异常了。
    不锁就抓异常吧
    private void TryCreateFolder() {
        // 循环:直到创建目录成功之后才退出循环
        while (true) {
            // 生成路径
            string path = GeneratePath();
            // 如果目录已经存在,那么生成另一个路径
            if (Directory.Exists(path)) {
                continue;
            } else {
                try { //目录不存在,那么成功创建之后,退出
                    Directory.CreateDirectory(path);
                    break;
                } catch { //创建失败,重新生成另一个路径
                    continue;
                }
            }
        }
    }
      

  6.   

    给个sb的意见,直接try上你的创建else // 目录不存在,那么创建之后,退出
                {
                    Directory.CreateDirectory(path);
                    return;
                }
    捕获异常后continue;
      

  7.   

    顺带提一句,生成的目录名有规则限制么?
    没限制干脆Guid.NewGuid()吧,又省事又省力,try...catch...都免了
      

  8.   

    另,while还是break出来吧,不建议直接return
      

  9.   


           private void Foo(Object obj)
            {
                while (true)
                {
                    Directory.CreateDirectory("c:\\1\\1");
                }
            }        private void button1_Click(object sender, EventArgs e)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
                ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), null);
            }你给我搞一个异常试试
      

  10.   

    好吧,你的实验让我发觉了一件事,不lock还真不行
    你的代码只是让我发觉,Directory.CreateDirectory不会在创建已有文件夹时报错,仅此而已。
    你能保证在一个线程的Directory.Exists与Directory.CreateDirectory之间,不会插入另一个线程的Directory.CreateDirectory么?
      

  11.   

    说个简单的实际情况
    ......
    线程x:Directory.Exists("c:\\1\\1")=false
    线程y:Directory.Exists("c:\\1\\1")=false
    线程x:Directory.CreateDirectory("c:\\1\\1")
    线程y:Directory.CreateDirectory("c:\\1\\1")
    ......好吧,本该创建2个不同文件夹的2个线程,最终只创建了一个文件夹
      

  12.   

    static void Main(string[] args) {
    for (int i = 0; i < 100; i++) {
    Thread t = new Thread(o => {
    Interlocked.Increment(ref j);
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString() + ":" + j.ToString());
    Thread.Sleep(1);
    Interlocked.Increment(ref j);
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString() + ":" + j.ToString());
    });
    t.Start();
    }
    Thread.Sleep(1000);
    Console.ReadKey();
    }
    private static int j;去看看运行结果吧!