2013-03-29 137 views
1

我有一个变量$ proxyManager,它是一个类ProxyManager的全局实例。 $ proxyManager = ProxyManager.new全局Ruby变量中的局部变量是否线程安全?

我在这个类中有一个函数getProxy,它被多个线程多次调用。在这个函数内部,我弹出一个数组中的项(让我们假设这是线程安全的)。然后,我将它的标识符设置为当前时间,设置一个活动标志并返回。

proxy.identifier在设置完成后在同一个线程中“更改”是否可能?例如,假设线程1将标识符设置为1,并且立即线程2,执行同一行并将其设置为2.这是否意味着线程1的标识符现在是2?

class ProxyManager 
    def getProxy 
     key = "proxy" 
     proxy = popFromGlobalArray() #assume this operation is thread-safe/atomic 

     proxy.identifier = Time.now.to_i 
     proxy.active = 1 
     return proxy 
    end 

end 
+0

有没有**共享数据**?也就是说,两个线程可以同时引用*相同的*代理对象吗? – 2013-03-29 22:55:56

回答

1

如果 popFromGlobalArray()函数正确地在多线程环境,并且不保证返回相同的对象不止一次,并且代理类不共享实例之间的执行状态,该函数的其余部分应精细。您不是在不同线程上操作相同的数据,因此它们不会发生冲突。

如果你担心变量本身,你不需要。本地方法是根据方法调用定义的,不同的线程将运行方法的不同调用。他们不分享当地人。

很明显,具体细节可以使这不太真实,但这是它通常如何工作。

1

局部变量是每个线程定义的,并且是线程安全的。

如果您的数组确实是原子的,则每次线程进入此函数时代理变量都会保证是不同的项目,而其他线程将无法覆盖该标识符。

3

这不是固有线程安全的,尽管这将取决于正是正在做什么。而且,实现 - 例如具有“绿色线程”的Ruby 1.8 MRI与Ruby 2 MRI与JRuby等 - 将在竞争条件(如果有的话)将如何实现方面发挥作用。

请记住,竞争条件通常是由共享数据引起的。这些变量并不重要(并且一个线程不会使用另一个线程局部变量,除非递归方法将重用变量),但变量命名的对象是重要。 (注:proxy局部变量proxy.instance局部变量!)

竞争条件假设共享数据/对象

proxy_A = popFromGlobalArray() 
proxy_B = popFromGlobalArray() 
# assume same object was returned so that proxy_A.equal? proxy_B is true 
proxy_A.identifier = Time.now.to_i 
proxy_A.active = 1 
proxy_B.identifier = Time.now.to_i # such that it is different 
proxy_B.active = 1 

这是不是很兴奋这里因为结果在这一点是一样的,但想象一下如果返回的对象(其中proxy_A和proxy_B refe r)已被用于之间的标识符变量的分配(和线程可见性传播) - 破码。

也就是说,假设上述扩展:

h = {} 
# assume same object was returned so that proxy_A.equal? proxy_B is true 
proxy_A.identifier = Time.now.to_i 
h[proxy_A.identifier] = proxy_A # i.e. used after return 
proxy_B.identifier = Time.now.to_i # such that it is different 
h[proxy_B.identifier] = proxy_B # i.e. used after return 
# now there may be an orphaned key/value. 

当然,如果popFromGlobalArray保证返回不同对象则以上不适用,还有另外一个问题 - 比赛情况取决于时间精度:

proxy_A = popFromGlobalArray() 
proxy_B = popFromGlobalArray() 
# assume Time.now.to_i returns x for both threads 
proxy_A.identifier = x 
proxy_B.identifier = x 
# and a lost proxy .. 
h = {} 
h[proxy_A.identifier] = proxy_A 
h[proxy_B.identifier] = proxy_B 

道德故事:不要依靠运气。我简化了上述内容,以显示线程间数据可见性可能发生的竞争条件。但是,线程之间的数据可见性(即缺少内存防护)使得这个问题远比最初看起来更糟糕。