我有一些必须是线程安全的代码,其行为类似于:
protected long m_RunningValue
protected long m_RunningCounter
protected object m_Lock = new object();
public long RunningValue { get { return Interlocked.Read(m_RunningValue); } }
public long RunningCounter { get { return Interlocked.Read(m_RunningCounter); } }
public void DoCalculation(int newValue, int newQuantity)
{
lock(m_Lock)
{
Interlocked.Add(ref m_RunningValueA, newValue);
Interlocked.Add(ref m_RunningCounter, newQuantity);
if(Interlocked.Read(ref newQuantity) == 0)
{
...m_RunningValue gets further modified here
}
}
}
计算必须锁定值和计数器,否则竞争条件可能影响if(...)块,但是在读出时它们根本不需要同步,即如果计数器和值在尝试之间发生变化读两个,这对我来说是100%的好.
读取时的互锁用于读取64位值的线程安全性.
混合联锁和锁这样安全吗?我在其他网页上看到混合它们是不安全的,但是如果这意味着混合它们是引入细微错误的好方法,或者如果在系统级别这会破坏所涉及的数据结构,我无法找到澄清.
所有这些互锁(64位.NET 4.0运行时)的成本是否完全违背了在属性get()方法周围保存ReaderWriterSlim锁的目的?
我们可以使用新的条件变量原语或windows事件来同步WinNT v6.x或更高版本中的线程.考虑以下两种方法,我们希望工作者在main中设置"go"的同时运行,否则它们都应该阻塞.
/*language C code*/
/*Windows Condition Variable*/
int go=0;
CONDITION_VARIABLE cv;
SRWLOCK lock;
void workers()
{
AcquireSRWLockShared(&lock);
if(go==0)
{
SleepConditionVariableSRW(&cv, &lock, INFINITE, CONDITION_VARIABLE_LOCKMODE_SHARED);
}
ReleaseSRWLockShared(&lock);
/*
Workers continue...
*/
}
void main()
{
int i;
InitializeConditionVariable(&cv);
InitializeSRWLock(&lock);
for(i=0;i<10;i++)
{
CreateThread(0, 0, workers, 0, 0, 0);
}
AcquireSRWLockExclusive(&lock);
go=1;
ReleaseSRWLockExclusive(&lock);
WakeAllConditionVariable(&cv);
}
Run Code Online (Sandbox Code Playgroud)
要么
/*language C code*/
/*Windows Event*/
HANDLE go;
void workers()
{
WaitForSingleObject(go, INFINITE);
/*
Workers continue...
*/
}
void main()
{
int i;
go=CreateEvent(0,1,0,0); /*No security descriptor, Manual …Run Code Online (Sandbox Code Playgroud) c windows multithreading condition-variable readerwriterlockslim
我非常熟悉,ReaderWriterLockSlim但我EnterUpgradeableReadLock()最近在一个类中尝试实现...不久之后我意识到当2个或更多线程运行代码时,这几乎肯定是一个保证死锁:
Thread A --> enter upgradeable read lock
Thread B --> enter upgradeable read lock
Thread A --> tries to enter write lock, blocks for B to leave read
Thread B --> tries to enter write lock, blocks for A to leave read
Thread A --> waiting for B to exit read lock
Thread B --> waiting for A to exit read lock
Run Code Online (Sandbox Code Playgroud)
我在这里错过了什么?
编辑
添加了我的场景的代码示例.该Run()方法将由两个或多个线程同时调用.
public class Deadlocker
{
private readonly ReaderWriterLockSlim _lock …Run Code Online (Sandbox Code Playgroud) 最近我一直在重构我的一些C#代码,我发现了一些双重检查锁定实践.那时我不知道这是一个不好的做法,我真的想摆脱它.
问题是我有一个应该被懒惰地初始化并且经常被许多线程访问的类.我也不想将初始化移动到静态初始化器,因为我计划使用弱引用来保持初始化对象在内存中保持太长时间.但是,如果需要,我想"恢复"对象,确保以线程安全的方式发生这种情况.
我想知道是否在C#中使用ReaderWriterLockSlim并在第一次检查之前输入UpgradeableReadLock,然后如果需要,为初始化输入写锁定将是可接受的解决方案.以下是我的想法:
public class LazyInitialized
{
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
private volatile WeakReference _valueReference = new WeakReference(null);
public MyType Value
{
get
{
MyType value = _valueReference.Target as MyType;
_lock.EnterUpgradeableReadLock();
try
{
if (!_valueReference.IsAlive) // needs initializing
{
_lock.EnterWriteLock();
try
{
if (!_valueReference.IsAlive) // check again
{
// prevent reading the old weak reference
Thread.MemoryBarrier();
_valueReference = new WeakReference(value = InitializeMyType());
}
}
finally
{
_lock.ExitWriteLock();
}
}
}
finally
{
_lock.ExitUpgradeableReadLock();
}
return value;
} …Run Code Online (Sandbox Code Playgroud) 我的应用程序中有一个有趣的死锁问题.有一个内存数据存储,它使用ReaderWriterLockSlim来同步读写.其中一种读取方法使用Parallel.ForEach在给定一组过滤器的情况下搜索商店.其中一个过滤器可能需要对同一商店进行恒定时间读取.这是产生死锁的场景:
更新:下面的示例代码.实际方法调用更新步骤
鉴于单一实例store的ConcreteStoreThatExtendsGenericStore
store.Search(someCriteria)store.Update()- 阻塞Thread1理想情况下,如果当前线程的祖先线程已经具有相同的锁,我想要做的就是不尝试获取读锁.有没有办法做到这一点?或者还有另一种/更好的方法吗?
public abstract class GenericStore<TKey, TValue>
{
private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
private List<IFilter> _filters; //contains instance of ExampleOffendingFilter
protected Dictionary<TKey, TValue> Store { get; private set; }
public void Update()
{
_lock.EnterWriterLock();
//update the store
_lock.ExitWriteLock();
}
public TValue GetByKey(TKey …Run Code Online (Sandbox Code Playgroud) 我想检查以下代码是否能够抵抗 ThreadAbortException 并且不会导致孤儿锁。如果不是,那么避免孤儿锁的最佳模式是什么?
ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
public void DoStaff()
{
_lock.EnterWriteLock();
//Is this place where ThreadAbotException can corrupt my code, or is there JIT optimalization which prevent this from happening???
try
{
...
}
finally
{
_lock.ExitWriteLock();
}
}
Run Code Online (Sandbox Code Playgroud)
根据以下链接http://chabster.blogspot.cz/2013/07/a-story-of-orphaned-readerwriterlockslim.html,有(或至少有)可能的方法如何创建孤儿锁,但我正在运行示例编码了一段时间,没有任何运气。
我正在使用.NET 4.0
调试和发布中的行为有什么区别吗?
我有一个在多个线程之间共享的字典.每个线程根据给定的键从字典中读取特定值,但是 - 如果字典中不存在该键,则线程需要将其添加到字典中.
为了解决同步问题,我虽然使用了ReaderWriterLockSlim类,它基本上给了我读者 - 作者锁定同步(意思是读者可以并行运行,但一次只能运行一个作者......)但为读者添加了升级选项.使用升级选项,我可以测试给定的密钥是否已经在字典中,如果没有 - 升级锁并写入它,承诺每个密钥只添加一个.
我的问题是,我不能一次创建两个可升级的锁 - 这意味着这个解决方案是不好的...... :(
有人可以向我解释为什么微软选择以这种方式实施可升级锁(我一次不能拥有多个可升级的锁......),并且让我知道如何通过自己实现可升级的锁\给我的另一个想法是同步我的共享字典?
我使用ConcurrentBag在运行时存储对象.在某些时候,我需要清空行李并将行李内容存储到列表中.这就是我做的:
IList<T> list = new List<T>();
lock (bag)
{
T pixel;
while (bag.TryTake(out pixel))
{
list.Add(pixel);
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是同步,据我在书中读到的锁比其他同步方法更快.来源 - http://www.albahari.com/threading/part2.aspx.
性能是我的第二个问题,我想知道我是否可以在此时使用ReaderWriterLockSlim.使用ReaderWriterLockSlim会有什么好处?原因是,我不希望此操作阻止传入的请求.
如果是,我应该使用可升级锁吗?
有任何想法吗 ?评论?
c# multithreading synchronization locking readerwriterlockslim
编辑:从我已经得到的答案中,我了解我提出的第一个解决方案,并不是真正的“不阻止读取”,因为只有一个线程可以输入可升级的锁,而在读取被释放之前不能采用写入锁...
所以我的问题是,如果不存在,如何以正确的方式使第一个解决方案成为“非阻塞读取”?
我试图了解两种非阻塞多线程读取的解决方案。以下两个解决方案之间有什么区别(也许我仍然不了解某些事情,但是我正在尝试):
/// <summary>
/// ReaderWriterLockSlim pattern
/// </summary>
public class ReadWriteLockCheck
{
Dictionary<string, object> _dict = new Dictionary<string, object>();
private ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
public void CreateByKey(string key)
{
_rwLock.EnterReadLock();
try
{
if (!_dict.ContainsKey(key)) //Non blocking read - Check if exists
{
_rwLock.EnterWriteLock(); //Lock
try
{
_dict.Add(key, new object());
}
finally
{
_rwLock.ExitWriteLock();
}
}
}
finally
{
_rwLock.ExitReadLock();
}
}
public bool GetByKey(string key)
{
_rwLock.EnterWriteLock();
try
{
if (_dict.ContainsKey(key)) //Non blocking read
{
return …Run Code Online (Sandbox Code Playgroud) 我有一个数据库写入操作队列,由一个专用线程管理。我有很多线程可以随时从数据库读取数据。
我使用 ReaderWriterLockSlim 进行读/写访问控制。
我的问题是 - 为什么不推荐 LockRecursionPolicy.SupportsRecursion?MSDN 文档说:
不建议在新开发中使用递归,因为它会引入不必要的复杂性并使您的代码更容易出现死锁。
这里怎么会出现死锁呢?例如,如果我在已获取 WriteReadLock 时尝试调用 EnterReadLock(并且我处于 SupportsRecursion 策略下),则会出现异常...
我写了一小段代码,可以快速读取和写入多个线程的字典.我使用ReaderWriterLockSlim来保护代码,并且仍然收到了涉嫌尝试添加重复密钥的异常.
ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
Dictionary<int, int> _dict = new Dictionary<int, int>();
public SafeDictionaryTester()
{
for (int i = 0; i < 7; i++)
{
_dict.Add(i, i);
}
}
internal void Execute()
{
for (int i = 7; i < 10000; i++)
{
if (i % 6 == 0)
new Thread(new ThreadStart(delegate { Print(6); })).Start();
else if (i % 5 == 0)
new Thread(new ThreadStart(delegate { Print(5); })).Start();
else if (i % 4 == 0)
new Thread(new ThreadStart(delegate { …Run Code Online (Sandbox Code Playgroud) 我对ReaderWriterLockSlim感到沮丧并且延迟了ExitWriteLock.为什么WriteLock在定时器中发布回调?
var _lock = new ReaderWriterLockSlim();
_lock.EnterWriteLock();
Assert.AreEqual(true, _lock.IsWriteLockHeld); // good
System.Threading.Timer timer = new Timer(state =>
{
_lock.ExitWriteLock(); //throws exception that lock is not held
}, null, 1, -1);
Thread.Sleep(1000);
Assert.AreEqual(false, _lock.IsWriteLockHeld);
Run Code Online (Sandbox Code Playgroud) 在FileWriter将由不同线程使用的类中,我当前使用a ReaderWriterLockSlim来防止当两个线程同时尝试写入文件时发生的错误,如下所示:
(1)
public class FileWriter
{
private ReaderWriterLockSlim readerWriterLock = new ReaderWriterLockSlim();
public void WriteToFile(string message)
{
try
{
this.readerWriterLock.EnterWriteLock();
// the writing happens here
}
finally
{
this.readerWriterLockSlim.ExitWriteLock();
}
}
}
Run Code Online (Sandbox Code Playgroud)
哪个确实有效.但在那之后,我读了那个ReaderWriterLockSlim工具IDisposable,所以我想知道是否
(2)
public class FileWriter
{
public void WriteToFile(string message)
{
using (ReaderWriterLockSlim readerWriterLockSlim = new ReaderWriterLockSlim())
{
readerWriterLockSlim.EnterWriteLock();
// the writing happens here
readerWriterLockSlim.ExitWriteLock();
}
}
}
Run Code Online (Sandbox Code Playgroud)
将是"更好"的方法,是否会引入一些新的缺点.我的直觉告诉我,每次调用该方法时我可能不应该创建一个新的ReaderWriterLockSlim,而只是一次(2) …