【发布时间】:2013-02-03 12:30:23
【问题描述】:
场景
我想下载资源。我不希望资源被多次下载。如果线程 a 下载资源 1 它应该被缓存,并且线程 b 应该等待并使用缓存的资源 1 如果它试图下载资源 1同时。如果线程c要下载资源2,应该不受线程a和b的影响。
尝试
我已经尝试实现以下场景:
using System;
using System.Collections.Generic;
using System.Threading;
namespace ConsoleApplication1
{
class ConditionalThreadLockingProgram
{
private static readonly object _lockObject = new object();
private static readonly Dictionary<int, string> Locks =
new Dictionary<int, string>();
private static readonly Dictionary<int, string> Resources =
new Dictionary<int, string>();
public static string GetLock(int resourceId)
{
lock (_lockObject)
{
if (Locks.ContainsKey(resourceId))
{
return Locks[resourceId];
}
return Locks[resourceId] = string.Format(
"Lock #{0}",
resourceId
);
}
}
public static void FetchResource(object resourceIdObject)
{
var resourceId = (int)resourceIdObject;
var currentLock = GetLock(resourceId);
lock (currentLock)
{
if (Resources.ContainsKey(resourceId))
{
Console.WriteLine(
"Thread {0} got cached: {1}",
Thread.CurrentThread.Name,
Resources[resourceId]
);
return;
}
Thread.Sleep(2000);
Console.WriteLine(
"Thread {0} downloaded: {1}",
Thread.CurrentThread.Name,
Resources[resourceId] = string.Format(
"Resource #{0}",
resourceId
)
);
}
}
static void Main(string[] args)
{
new Thread(FetchResource) { Name = "a" }.Start(1);
new Thread(FetchResource) { Name = "b" }.Start(1);
new Thread(FetchResource) { Name = "c" }.Start(2);
Console.ReadLine();
}
}
}
问题
有效吗?有什么问题吗?
【问题讨论】:
-
是的,我认为它有效。但我对多线程非常陌生。
-
我可能会建议使用字典的 SyncRoot 而不是创建自己的锁。 GetLock 将使用 (((IDictionary)Locks).SyncRoot),FetchResouce 将使用 (((IDictionary)Resources).SyncRoot)
-
如果您正在寻找有关工作代码的反馈,将您的问题发布到codereview.stackexchange.com 可能更合适。
-
moncadad:谢谢您的建议。有人说使用
SyncRoot属性可能很危险:stackoverflow.com/questions/327654/… -
dgvid:感谢您告诉我有关 codereview.stackexchange.com 的信息。以前从未使用过该网站。我觉得这个问题是关于在同一个方法中使用不同的锁对象的概念。我觉得这是一个笼统的问题,需要一个例子来说明。
标签: c# multithreading thread-safety