假设我有一个包含队列的模块。
对于Enqueue的其他实体,它们必须通过一个函数:
public sub InsertIntoQueue(Obj)
MyQueue.Enqueue(Obj)
end sub
如果我有多个线程正在运行并且想要调用InsertIntoQueue(),这被认为是线程安全的吗?
我的印象是,在执行InsertIntoQueue()函数所需的内存中只有一个指令副本...这会让我认为这是线程安全的。
但是,我想知道当两个线程同时尝试运行该函数时会发生什么?
这个线程是否安全,如果没有,我怎样才能使线程安全? (以及关于速度和内存使用的性能影响)
答案 0 :(得分:8)
使用Queue.Synchronized包装。
答案 1 :(得分:4)
这不是线程安全的。
此类型的公共静态(在Visual Basic中为Shared)成员对于多线程操作是安全的。实例成员不保证是线程安全的。
来自MSDN Site。
我建议添加一个对象来表示对象的同步句柄
Dim SyncHandle as Object = new Object()
并修改您的方法
Public Sub InsertIntoQueue(Object item)
SyncLock SyncHandle
MyQueue.Enqueue(item)
End SyncLock
End Sub
答案 2 :(得分:2)
做
SyncLock MyQueue
MyQueue.Enqueue(Obj)
End SyncLock
End Sub
答案 3 :(得分:1)
一组指令并不意味着它是线程安全的。就指令而言,你总是只有一套。
现在,查看您提供的代码示例,无法确定它是否是线程安全的。所有标准.NET集合(包括Queue)本身都不是线程安全的,但是可以访问自己的同步版本。
现在在性能方面,当然会有性能损失,有多大 - 这取决于锁的范围和其他一些东西。特别是在Web应用程序中使用全局锁定可能会成为负载下的严重瓶颈
答案 4 :(得分:0)
冒着稍微偏离OP主题的风险,应该考虑队列的其他方法。我假设至少有一个线程出队对象,你可能还在检查队列是否为空?
从出列的角度看,如果你有多个线程出队,并且在调用dequeue之前检查队列是否为空(以防止无效的操作异常),那么一个线程(线程a)可能完全可能将队列中的最后一项出列,在另一个线程(线程b)之间读取队列不为空并且调用dequeue,因此线程a将导致无效操作异常。
你可以将支票放在支票周围为空,然后出队以解决这个问题。
This和this是有关线程安全性的有趣文章,我也建议您阅读this和/或this,但它们并非都在vb中。他们详细解释了线程。
答案 5 :(得分:0)
我不是线程安全方面的专家,但我正在尽可能多地学习这个问题。
我曾经认为(像你一样)这个操作可以是线程安全的,就像写入不同线程上的队列数据一样,并且没有出现队列号。但正如有人在这里解释的那样(并且在MSDN文档中无处不在):
公共静态(在Visual Basic中共享) 这种类型的成员是安全的 多线程操作。例 会员不能保证 线程安全的。
这意味着可能在内部MyQueue.Enqueue(Obj)
就像这样:
如果以这种方式完成,你将遇到线程问题,因为你可以看到你可以用两个线程覆盖队列中的相同位置,因为一个是在其他人做了相同的但仍然无法写入已经递增指针。
考虑到这一点,你有几个选项,如此处所述,使用Queue.Synchronized()锁定Enqueue()方法,或者甚至更简单但对性能影响更大,在访问Queue对象时锁定私有属性以这种方式(因为你对Queue做的任何事情都不是线程安全的):
Private ReadOnly Property MyQueue() as Queue
Get
SyncLock (m_myQueueLock)
Return m_myQueue
EndSyncLock
End Get
End Property
希望这有帮助!