我正在设计和开发一个api,其中多个线程正在从网络下载文件,然后将其写入磁盘。
如果使用不当,可能会发生同一文件被多个线程下载和写入的情况,这将导致在写入磁盘时出现异常。
我希望避免在写入文件的部分周围使用lock() { ... },但显然我不想使用全局对象锁定,只是与特定文件相关的内容,这样在写入文件时并不会锁定所有线程。
我希望这个问题可以理解。
发布于 2014-04-28 14:23:43
您可以考虑使用ReaderWriterLockSlim
http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx
private ReaderWriterLockSlim fileLock = new ReaderWriterLockSlim();
fileLock.EnterWriteLock();
try
{
//write your file here
}
finally
{
fileLock.ExitWriteLock();
}发布于 2014-04-28 15:04:54
因此,您想要做的是同步一组没有给定键的操作。在这种情况下,该键可以是一个绝对文件名。我们可以将其实现为将键映射到某些同步对象的字典。如果我们想要实现阻塞同步机制,这可以是一个要锁定的对象,或者如果我们希望在适当的时候表示运行代码的异步方法,则可以是一个Task;我还使用了一个ConcurrentDictionary来让它处理同步,而不是手动处理它,并使用Lazy来确保每个任务只创建一次:
public class KeyedSynchronizer<TKey>
{
private ConcurrentDictionary<TKey, Lazy<Task>> dictionary;
public KeyedSynchronizer(IEqualityComparer<TKey> comparer = null)
{
dictionary = new ConcurrentDictionary<TKey, Lazy<Task>>(
comparer ?? EqualityComparer<TKey>.Default);
}
public Task ActOnKey(TKey key, Action action)
{
var dictionaryValue = dictionary.AddOrUpdate(key,
new Lazy<Task>(() => Task.Run(action)),
(_, task) => new Lazy<Task>(() =>
task.Value.ContinueWith(t => action())));
return dictionaryValue.Value;
}
public static readonly KeyedSynchronizer<TKey> Default =
new KeyedSynchronizer<TKey>();
}现在可以创建此同步器的一个实例,然后与它们对应的键(文件)一起指定操作。您可以确信,在该文件上的任何先前操作完成之前,不会执行这些操作。如果您想要等待到该操作完成,那么您可以在任务上Wait,如果您没有任何需要等待,那么您就不能。这还允许您通过等待任务异步完成处理。
发布于 2014-04-28 14:30:42
我也遇到过类似的情况,并通过对所讨论的lock()对象进行StreamWriter处理来解决这个问题:
private Dictionary<string, StreamWriter> _writers; // Consider using a thread-safe dictionary
void WriteContent(string file, string content)
{
StreamWriter writer;
if (_writers.TryGetValue(file, out writer))
lock (writer)
writer.Write(content);
// Else handle missing writer
}这是从内存中得到的,它可能不会编译。我读了安德鲁的解决方案(我会的),因为这可能是你所需要的.但这太简单了,如果你只是想要一个既快又脏的。
https://stackoverflow.com/questions/23343490
复制相似问题