Ruby on rails 全局Ruby变量中的局部变量是线程安全的吗?

Ruby on rails 全局Ruby变量中的局部变量是线程安全的吗?,ruby-on-rails,ruby,multithreading,Ruby On Rails,Ruby,Multithreading,我有一个变量$proxyManager,它是类proxyManager的全局实例。 $proxyManager=proxyManager.new 我在这个类中有一个函数getProxy,它被多个线程多次调用。在这个函数中,我从数组中弹出一个项(假设这是线程安全的)。然后,我将其标识符设置为当前时间,设置一个活动标志,并返回它 proxy.identifier在设置后是否可能在同一线程中“更改”?例如,假设线程1将标识符设置为1,线程2立即执行同一行并将其设置为2。这是否意味着线程1的标识符现在是

我有一个变量$proxyManager,它是类proxyManager的全局实例。 $proxyManager=proxyManager.new

我在这个类中有一个函数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

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


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

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

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

它本身不是线程安全的,尽管它将完全取决于正在执行的操作和要执行的操作。此外,该实现——例如带有“绿色线程”的Ruby1.8MRI、Ruby2MRI和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都引用)已在标识符变量的赋值(和线程可见性传播)之间使用-断开的代码

也就是说,假设上述内容已展开:

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
这个故事的寓意是:不要依赖运气。我简化了上面的内容,以显示线程间数据即时可见时可能出现的竞争条件。但是,线程之间的数据可见性(即缺少内存围栏)使此问题比最初看起来更糟。

虽然它本质上不是线程安全的,但具体取决于正在执行的操作和执行的操作。此外,该实现——例如带有“绿色线程”的Ruby1.8MRI、Ruby2MRI和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都引用)已在标识符变量的赋值(和线程可见性传播)之间使用-断开的代码

也就是说,假设上述内容已展开:

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

这个故事的寓意是:不要依赖运气。我简化了上面的内容,以显示线程间数据即时可见时可能出现的竞争条件。但是,线程之间的数据可见性(即缺少内存围栏)使此问题比最初看起来更严重。

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

如果你担心变量本身,你不必担心。每个方法调用都定义了局部变量,不同的线程将运行不同的方法调用。他们不是本地人


显然,这些细节可能会使这一点变得不那么真实,但这是它通常的工作方式。

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

如果你担心变量本身,你不必担心。每个方法调用都定义了局部变量,不同的线程将运行不同的方法调用。他们不是本地人

很明显,这些细节可能会使这一点变得不那么真实,但这就是它通常的工作原理。

是否有任何共享数据?也就是说,两个线程是否可以同时引用同一个代理对象?是否存在任何共享数据?也就是说,两个线程是否可以同时引用同一个代理对象?