我有一个队列对象,我需要确保线程安全。是否最好使用这样的锁对象:
lock(myLockObject)
{
//do stuff with the queue
}还是建议像这样使用Queue.Synchronized:
Queue.Synchronized(myQueue).whatever_i_want_to_do();在读取MSDN文档时,它说我应该使用Queue.Synchronized使其线程安全,但随后给出了一个使用lock对象的示例。来自MSDN的文章:
为了保证队列的线程安全,所有操作必须仅通过此包装器完成。
枚举集合本质上不是一个线程安全的过程。即使在同步集合时,其他线程仍然可以修改集合,这将导致枚举数抛出异常。要确保枚举期间的线程安全,可以在整个枚举期间锁定集合,或者捕获其他线程所做更改导致的异常。
如果调用同步()不能确保线程安全,那么它有什么意义呢?我是不是漏掉了什么?
发布于 2008-12-03 21:25:12
就我个人而言,我总是更喜欢上锁。这意味着你可以决定粒度。如果您只依赖于同步包装器,那么每个单独的操作都是同步的,但是如果您需要做不止一件事情(例如,迭代整个集合),那么无论如何您都需要锁定。为了简单起见,我只想记住一件事--适当地锁定!
编辑:正如注释中所指出的,如果您可以使用更高级别的抽象,那就太好了。如果您确实使用了锁定,那么要小心--记录您期望锁定在何处的内容,并尽可能短地获取/释放锁(更多的是为了正确性而不是性能)。在持有锁时避免调用未知代码,避免嵌套锁等。
在.NET 4中,支持更高级别的抽象(包括无锁代码)。不管怎样,我还是不建议使用同步包装器。
发布于 2008-12-03 21:49:54
旧集合库中的Synchronized方法存在一个主要问题,因为它们在粒度太低的情况下同步(每种方法而不是每个工作单元)。
有一个典型的同步队列的争用条件,如下所示,您将检查Count以查看去队列是否安全,但是Dequeue方法会抛出一个指示队列为空的异常。这是因为每个单独的操作都是线程安全的,但是Count的值可以在查询它时和使用该值时进行更改。
object item;
if (queue.Count > 0)
{
// at this point another thread dequeues the last item, and then
// the next line will throw an InvalidOperationException...
item = queue.Dequeue();
}您可以使用手动锁安全地编写整个工作单元(即检查计数并将项目排除队列)如下:
object item;
lock (queue)
{
if (queue.Count > 0)
{
item = queue.Dequeue();
}
}因此,由于您无法从同步队列中安全地排出任何队列,所以我不会去理会它,而只会使用手动锁定。
.NET 4.0应该有大量正确实现的线程安全集合,但不幸的是,这还需要将近一年的时间。
发布于 2008-12-03 22:29:24
这样,我们就不需要锁定队列就可以发现队列是空的。
object item;
if (queue.Count > 0)
{
lock (queue)
{
if (queue.Count > 0)
{
item = queue.Dequeue();
}
}
}https://stackoverflow.com/questions/338712
复制相似问题