请教:C#加锁的问题

BuleRiver 2013-01-04 10:32:56
大家好,我想实现这样的一个需求:
随机生成一个目录名称,如果这个目录不存在,那么就创建,如果存在,就重新生成,直到目录不存在并生成为止,但是运行这段代码的线程可能有成千上万个,所以需要加锁,并且效率要尽可能高。
我是这样想的:判断目录是否存在、创建新的目录,这应该是一个原子操作。但是如果两个线程生成的不是同一个路径,那么它们就不应该互斥,只有在生成的目录名称完全相同时,才需要互斥。
例如:
线程1生成的path="C:\folder1"
线程2生成的path="C:\folder1"
由于线程1和线程2生成的路径相同,所以应该进行互斥操作,避免出错。
但是如果:
线程1生成的path="C:\folder1"
线程2生成的path="C:\folder2"
由于线程1和线程2生成的路径不相同,所以不需要进行互斥操作。
不知道如何实现该需求?或者应该使用哪个锁?
谢谢大家。
...全文
619 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
u010116514 2013-04-01
  • 打赏
  • 举报
回复
创建文件夹会异常?就算文件夹存在,我再创建也可以的啊,只是覆盖而已,文件夹里面的东西不会改变和删除。至于想的那么复杂吗
BuleRiver 2013-01-05
  • 打赏
  • 举报
回复
引用 24 楼 lorl2 的回复:
楼主,按你的这个需求来说,单线程模型才是最适合你的。 首先,硬盘读写是线性读写性能是最高的,也就是说一个线程专门负责去读写效率是最高的。 其次,你的业务逻辑也不适合多线程,单单线程间的切换开销就是很大的了,你的线程处理时间相于切换时间的比值太低,大量的重复你这个处理逻辑的时候,线程切换的开销就可当可观了。另外,由于多线程同步带来的锁开销也是相当大的。 ……
我在写接口,一直是多线程的模型,不能修改啊。呵呵。
Marky 2013-01-04
  • 打赏
  • 举报
回复
		private object thisLock = new object();

		public void YourThreading() {
			string temppath;
			//ToDo Something
			lock (thisLock) {
				if (Directory.Exists(temppath)) {
					Directory.CreateDirectory(temppath);
				}else{
					//ToDo Something
				}
			}
		}
hard_learner 2013-01-04
  • 打赏
  • 举报
回复
我理解的他的意思应该是这个目录不存在的时候同时生成了相同的路径需要进行创建吧,这种情况可以采用双重锁
Assassin_ 2013-01-04
  • 打赏
  • 举报
回复
如果这个目录不存在,那么就创建,如果存在,就重新生成 --> 你这个需求不符合互斥条件么。
lorl2 2013-01-04
  • 打赏
  • 举报
回复
楼主,按你的这个需求来说,单线程模型才是最适合你的。 首先,硬盘读写是线性读写性能是最高的,也就是说一个线程专门负责去读写效率是最高的。 其次,你的业务逻辑也不适合多线程,单单线程间的切换开销就是很大的了,你的线程处理时间相于切换时间的比值太低,大量的重复你这个处理逻辑的时候,线程切换的开销就可当可观了。另外,由于多线程同步带来的锁开销也是相当大的。
DSIOF3KIDSKTR 2013-01-04
  • 打赏
  • 举报
回复
不知道你具体的需求背景是什么,创建文件夹需要用到多线程吗?多线程在单核和非多核心非并行编程中基本上比单线程的真正优点应该就是在防止阻塞造成的时间耽搁,否则在非多核心非并行编程中多线程的理论效率应该是低于单线程的,它还要维护线程。
Marky 2013-01-04
  • 打赏
  • 举报
回复
		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;
去看看运行结果吧!
Marky 2013-01-04
  • 打赏
  • 举报
回复
引用 20 楼 SocketUpEx 的回复:
能保证
拿什么保证?线程安全?扯淡
SocketUpEx 2013-01-04
  • 打赏
  • 举报
回复
引用 18 楼 marclee44 的回复:
你能保证在一个线程的Directory.Exists与Directory.CreateDirectory之间,不会插入另一个线
能保证
Marky 2013-01-04
  • 打赏
  • 举报
回复
说个简单的实际情况 ...... 线程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个线程,最终只创建了一个文件夹
Marky 2013-01-04
  • 打赏
  • 举报
回复
引用 17 楼 SocketUpEx 的回复:
你给我搞一个异常试试
好吧,你的实验让我发觉了一件事,不lock还真不行 你的代码只是让我发觉,Directory.CreateDirectory不会在创建已有文件夹时报错,仅此而已。 你能保证在一个线程的Directory.Exists与Directory.CreateDirectory之间,不会插入另一个线程的Directory.CreateDirectory么?
SocketUpEx 2013-01-04
  • 打赏
  • 举报
回复
引用 11 楼 marclee44 的回复:
引用 10 楼 SocketUpEx 的回复:都说不用加锁了 线程安全的 如果只有Directory.CreateDirectory这一个I/O操作,那么是没必要 但如果某线程在Directory.Exists时返回了false,另一个线程却在之后立即创建了同名文件夹呢?Directory.CreateDirectory异常了。 不锁就抓异常吧
       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);
        }
你给我搞一个异常试试
Marky 2013-01-04
  • 打赏
  • 举报
回复
另,while还是break出来吧,不建议直接return
Marky 2013-01-04
  • 打赏
  • 举报
回复
引用 13 楼 haiyun141 的回复:
额,怎么发了下呆,楼上答案 和我一样。。。。
Marky 2013-01-04
  • 打赏
  • 举报
回复
顺带提一句,生成的目录名有规则限制么? 没限制干脆Guid.NewGuid()吧,又省事又省力,try...catch...都免了
haiyun141 2013-01-04
  • 打赏
  • 举报
回复
引用 11 楼 marclee44 的回复:
引用 10 楼 SocketUpEx 的回复:都说不用加锁了 线程安全的 如果只有Directory.CreateDirectory这一个I/O操作,那么是没必要 但如果某线程在Directory.Exists时返回了false,另一个线程却在之后立即创建了同名文件夹呢?Directory.CreateDirectory异常了。 不锁就抓异常吧 C# code?……
额,怎么发了下呆,楼上答案 和我一样。。。。
haiyun141 2013-01-04
  • 打赏
  • 举报
回复
给个sb的意见,直接try上你的创建else // 目录不存在,那么创建之后,退出 { Directory.CreateDirectory(path); return; } 捕获异常后continue;
Marky 2013-01-04
  • 打赏
  • 举报
回复
引用 10 楼 SocketUpEx 的回复:
都说不用加锁了 线程安全的
如果只有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;
            }
        }
    }
}
SocketUpEx 2013-01-04
  • 打赏
  • 举报
回复
都说不用加锁了 线程安全的
加载更多回复(6)

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧