Interlocked.在32位系统上添加不带线程安全线程 [英] Interlocked.Add Not Thread Safe with Longs on a 32bit system

查看:49
本文介绍了Interlocked.在32位系统上添加不带线程安全线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是控制台应用程序的三个类。如果分成三个单独的文件,子main()将启动多个线程添加和

删除相同的值。最后,我们期望所有

余额的值为0.使用整数时,一切正常。 LONGS做

没有。


我们正在使用Interlocked方法。我相信在32位系统上使用long时,Interlocked.Add

方法不是线程安全的。


我们知道Interlocked.Read(dotnet 2.0的新功能) )对于32位系统上的多头需要

,但是dotnet框架错过了一个技巧

这里微软推出了一种新的阅读方法但是没有

使.Add方法正常工作。


注意:这可以在单核单个procssors上找到。

但是没有在多核或双核或超线程奔腾4上。


选项明确开启


选项严格上
< br $>
模块模块1


公共柜员(99)作为柜员


私人主题(99)As Threading.Thread


Sub Main()


我的整数= 0到99

Tellers(我)=新出纳员


下一页





我的整数= 0到99


昏暗t As New Threading.Thread(AddressOf

Tellers(i).DoWork)


主题(i)= t


t.Start()


下一页


我的整数= 0到99

主题(i).Join()


下一页


Dim B2 As Integer = BankInt.Balance


Console.WriteLine(" Int Balance" &安培; B2)


Dim B1 As Long = BankLong.Balance


Console.WriteLine(Long Balance"& B1)


循环


结束子


结束模块


>

明确选项


选项严格上限


进口System.Threading

公共班级柜员


Public Sub DoWork()


我的整数= 1到100000
< br $>
BankInt.Deposit(50)


BankInt.Withdraw(50)


BankLong.Deposit(50)


BankLong.Withdraw(50)


下一页


End Sub


结束班级


选项明确开启


选项严格开启


进口系统。线程


公共类BankLong


私人共享_balance持续


公共共享ReadOnly Property Balance()As Long


获取


返回Interlocked.Read(_balance)


结束获取


结束物业


公共共享子存款(ByVal金额一样长)


Interlocked.Add(_balance,Amount)


结束子


公共共享子提款(ByVal金额一样长)


Interlocked.Add(_balance,-Amount)


结束子


结束班


公共类BankInt


私有共享_balance作为整数


公共共享ReadOnly财产余额()为整数


获取


返回_balance


结束获取


结束物业


公共共享子存款(ByVal金额为整数)


Interlocked.Add(_balance,Amount)


End Sub


公共共享子提款(ByVal Amount As整数)


Interlocked.Add(_balance,-Amount)


End Sub


结束班

解决方案

大卫,


Interlocked.Add是线程-safe for Int64。那么问题出在哪里?请仔细看看
的Withdrawl方法。你正在做一个无锁的

对Int64的否定。


Brian


David写道:


以下是控制台应用程序的三个类。如果分成三个单独的文件,子main()将启动多个线程添加和

删除相同的值。最后,我们期望所有

余额的值为0.使用整数时,一切正常。 LONGS做

没有。


我们正在使用Interlocked方法。我相信在32位系统上使用long时,Interlocked.Add

方法不是线程安全的。


我们知道Interlocked.Read(dotnet 2.0的新功能) )对于32位系统上的多头需要

,但是dotnet框架错过了一个技巧

这里微软推出了一种新的阅读方法但是没有

使.Add方法正常工作。


注意:这可以在单核单个procssors上找到。

但是没有在多核或双核或超线程奔腾4上。


选项明确开启


选项严格上


模块模块1



公共柜员(99)作为柜员


私人话题(99)As Threading.Thread



Sub Main()


我的整数= 0到99


Tellers(i)=新柜员


下一页






对于i as Integer = 0到99

Dim t As New Threading.Thread(AddressOf

Tellers(i).DoWork )


主题(i)= t


t.Start()


下一步


我的整数= 0到99

线程(i).Join()


下一页


Dim B2 As Integer = BankInt.Balance


Console.WriteLine(" Int Balance" &安培; B2)


Dim B1 As Long = BankLong.Balance


Console.WriteLine(Long Balance"& B1)


循环



结束次级


结束模块



明确选项


选项严格开启


进口System.Threading

公共班级柜员


公共子工作()


我的整数= 1到100000


BankInt.Deposit(50)


BankInt.Withdraw(50)


BankLong.Deposit (50)


BankLong.Withdraw(50)


下一页


End Sub


结束课



选项明确开启


期权严格开启


进口系统。线程


公共类BankLong


私人共享_bal很长时间


公共资源ReadOnly财产余额()长期


获取


返回Interlocked.Read(_balance)


结束获取


结束物业


公共共享次级存款(ByVal金额一样长)


Interlocked.Add(_balance,金额)


结束子


Public Shared Sub Withdraw(ByVal Amount as Long)


Interlocked.Add(_balance,-Amount)


End Sub

结束班级


公共类别BankInt


私人共享_balance作为整数

公共共享ReadOnly财产余额()为整数


获取


返回_balance


结束获取


结束物业


公共共享次级存款(ByVal金额为整数)


Interlocked.Add(_balance,Amount)


End Sub


公共共享子提款(ByVal金额为整数)

/>
Interlocked.Add(_balance,-Amount)


结束子


结束等级




Brian Gideon写道:


David,


Interlocked.Add对Int64是线程安全的。那么问题出在哪里?请仔细看看
的Withdrawl方法。你正在做一个无锁的

否定Int64。


Brian


$ b $嗯......我相信我说得太早了。我刚注意到

Withdraw方法中的金额在堆栈中。当我有时间时,我将不得不用一点点来看看这个。


David,


我只是没有看到代码有问题。好吧,除了你

真的需要一个电话Interlocked.Read在BankInt.Balance属性,

但这不会导致你看到的问题。我会尝试

记得在我的双核笔记本电脑上运行这个代码(不是我在

时刻),它上面有VS 2005。 />

最后看到多少余额?


Brian


David写道:


以下是控制台应用程序的三个类。如果分成三个单独的文件,子main()将启动多个线程添加和

删除相同的值。最后,我们期望所有

余额的值为0.使用整数时,一切正常。 LONGS做

没有。


我们正在使用Interlocked方法。我相信在32位系统上使用long时,Interlocked.Add

方法不是线程安全的。


我们知道Interlocked.Read(dotnet 2.0的新功能) )对于32位系统上的多头需要

,但是dotnet框架错过了一个技巧

这里微软推出了一种新的阅读方法但是没有

使.Add方法正常工作。


注意:这可以在单核单个procssors上找到。

但是没有在多核或双核或超线程奔腾4上。


选项明确开启


选项严格上


模块模块1



公共柜员(99)作为柜员


私人话题(99)As Threading.Thread



Sub Main()


我的整数= 0到99


Tellers(i)=新柜员


下一页






对于i as Integer = 0到99

Dim t As New Threading.Thread(AddressOf

Tellers(i).DoWork )


主题(i)= t


t.Start()


下一步


我的整数= 0到99

线程(i).Join()


下一页


Dim B2 As Integer = BankInt.Balance


Console.WriteLine(" Int Balance" &安培; B2)


Dim B1 As Long = BankLong.Balance


Console.WriteLine(Long Balance"& B1)


循环



结束次级


结束模块



明确选项


选项严格开启


进口System.Threading

公共班级柜员


公共子工作()


我的整数= 1到100000


BankInt.Deposit(50)


BankInt.Withdraw(50)


BankLong.Deposit (50)


BankLong.Withdraw(50)


下一页


End Sub


结束课



选项明确开启


期权严格开启


进口系统。线程


公共类BankLong


私人共享_bal很长时间


公共资源ReadOnly财产余额()长期


获取


返回Interlocked.Read(_balance)


结束获取


结束物业


公共共享次级存款(ByVal金额一样长)


Interlocked.Add(_balance,金额)


结束子


Public Shared Sub Withdraw(ByVal Amount as Long)


Interlocked.Add(_balance,-Amount)


End Sub

结束班级


公共类别BankInt


私人共享_balance作为整数

公共共享ReadOnly财产余额()为整数


获取


返回_balance


结束获取


结束物业


公共共享次级存款(ByVal金额为整数)


Interlocked.Add(_balance,Amount)


End Sub


公共共享子提款(ByVal金额为整数)

/>
Interlocked.Add(_balance,-Amount)


结束子


结束等级

Below are three classes for a console application. If put into three
separate files, the sub main() will launch multiple threads adding and
removing the same value. At the end we expect the value for all
Balances to be 0. When using an Integer things work fine. LONGS do
not.

We are using the Interlocked methods. I believe the Interlocked.Add
method is not thread safe when using longs on 32bit systems.

We are aware of Interlocked.Read (new to dotnet 2.0) which is required
for longs on 32bit systems, but is the dotnet framework missing a trick
here as Microsoft have introduced a new method for reading but haven''t
got the .Add method to work correctly.

Note: This works find on single core single procssors.
But does not on muli-core or dual-core or hyper-threaded pentium 4.

Option Explicit On

Option Strict On

Module Module1

Public Tellers(99) As Teller

Private Threads(99) As Threading.Thread

Sub Main()

For i As Integer = 0 To 99

Tellers(i) = New Teller

Next

Do

For i As Integer = 0 To 99

Dim t As New Threading.Thread(AddressOf
Tellers(i).DoWork)

Threads(i) = t

t.Start()

Next

For i As Integer = 0 To 99

Threads(i).Join()

Next

Dim B2 As Integer = BankInt.Balance

Console.WriteLine("Int Balance " & B2)

Dim B1 As Long = BankLong.Balance

Console.WriteLine("Long Balance " & B1)

Loop

End Sub

End Module



Option Explicit On

Option Strict On

Imports System.Threading

Public Class Teller

Public Sub DoWork()

For i As Integer = 1 To 100000

BankInt.Deposit(50)

BankInt.Withdraw(50)

BankLong.Deposit(50)

BankLong.Withdraw(50)

Next

End Sub

End Class

Option Explicit On

Option Strict On

Imports System.Threading

Public Class BankLong

Private Shared _balance As Long

Public Shared ReadOnly Property Balance() As Long

Get

Return Interlocked.Read(_balance)

End Get

End Property

Public Shared Sub Deposit(ByVal Amount As Long)

Interlocked.Add(_balance, Amount)

End Sub

Public Shared Sub Withdraw(ByVal Amount As Long)

Interlocked.Add(_balance, -Amount)

End Sub

End Class

Public Class BankInt

Private Shared _balance As Integer

Public Shared ReadOnly Property Balance() As Integer

Get

Return _balance

End Get

End Property

Public Shared Sub Deposit(ByVal Amount As Integer)

Interlocked.Add(_balance, Amount)

End Sub

Public Shared Sub Withdraw(ByVal Amount As Integer)

Interlocked.Add(_balance, -Amount)

End Sub

End Class

解决方案

David,

Interlocked.Add is thread-safe for Int64. So where''s the problem? Take
a closer look at the Withdrawl method. You''re doing a lock-free
negation of an Int64.

Brian

David wrote:

Below are three classes for a console application. If put into three
separate files, the sub main() will launch multiple threads adding and
removing the same value. At the end we expect the value for all
Balances to be 0. When using an Integer things work fine. LONGS do
not.

We are using the Interlocked methods. I believe the Interlocked.Add
method is not thread safe when using longs on 32bit systems.

We are aware of Interlocked.Read (new to dotnet 2.0) which is required
for longs on 32bit systems, but is the dotnet framework missing a trick
here as Microsoft have introduced a new method for reading but haven''t
got the .Add method to work correctly.

Note: This works find on single core single procssors.
But does not on muli-core or dual-core or hyper-threaded pentium 4.

Option Explicit On

Option Strict On

Module Module1

Public Tellers(99) As Teller

Private Threads(99) As Threading.Thread

Sub Main()

For i As Integer = 0 To 99

Tellers(i) = New Teller

Next

Do

For i As Integer = 0 To 99

Dim t As New Threading.Thread(AddressOf
Tellers(i).DoWork)

Threads(i) = t

t.Start()

Next

For i As Integer = 0 To 99

Threads(i).Join()

Next

Dim B2 As Integer = BankInt.Balance

Console.WriteLine("Int Balance " & B2)

Dim B1 As Long = BankLong.Balance

Console.WriteLine("Long Balance " & B1)

Loop

End Sub

End Module



Option Explicit On

Option Strict On

Imports System.Threading

Public Class Teller

Public Sub DoWork()

For i As Integer = 1 To 100000

BankInt.Deposit(50)

BankInt.Withdraw(50)

BankLong.Deposit(50)

BankLong.Withdraw(50)

Next

End Sub

End Class

Option Explicit On

Option Strict On

Imports System.Threading

Public Class BankLong

Private Shared _balance As Long

Public Shared ReadOnly Property Balance() As Long

Get

Return Interlocked.Read(_balance)

End Get

End Property

Public Shared Sub Deposit(ByVal Amount As Long)

Interlocked.Add(_balance, Amount)

End Sub

Public Shared Sub Withdraw(ByVal Amount As Long)

Interlocked.Add(_balance, -Amount)

End Sub

End Class

Public Class BankInt

Private Shared _balance As Integer

Public Shared ReadOnly Property Balance() As Integer

Get

Return _balance

End Get

End Property

Public Shared Sub Deposit(ByVal Amount As Integer)

Interlocked.Add(_balance, Amount)

End Sub

Public Shared Sub Withdraw(ByVal Amount As Integer)

Interlocked.Add(_balance, -Amount)

End Sub

End Class



Brian Gideon wrote:

David,

Interlocked.Add is thread-safe for Int64. So where''s the problem? Take
a closer look at the Withdrawl method. You''re doing a lock-free
negation of an Int64.

Brian

Hmm...I believe I spoke too soon. I just noticed that Amount in the
Withdraw method is on the stack. I''ll have to look at this in a little
more detail when I get time.


David,

I''m just not seeing a problem with the code. Well, except that you
really need a call Interlocked.Read in the BankInt.Balance property,
but that wouldn''t cause the problem you''re seeing. I''ll try to
remember to run this code on my dual-core laptop (not with me at the
moment) which has VS 2005 on it.

What balance are seeing at the end with longs?

Brian

David wrote:

Below are three classes for a console application. If put into three
separate files, the sub main() will launch multiple threads adding and
removing the same value. At the end we expect the value for all
Balances to be 0. When using an Integer things work fine. LONGS do
not.

We are using the Interlocked methods. I believe the Interlocked.Add
method is not thread safe when using longs on 32bit systems.

We are aware of Interlocked.Read (new to dotnet 2.0) which is required
for longs on 32bit systems, but is the dotnet framework missing a trick
here as Microsoft have introduced a new method for reading but haven''t
got the .Add method to work correctly.

Note: This works find on single core single procssors.
But does not on muli-core or dual-core or hyper-threaded pentium 4.

Option Explicit On

Option Strict On

Module Module1

Public Tellers(99) As Teller

Private Threads(99) As Threading.Thread

Sub Main()

For i As Integer = 0 To 99

Tellers(i) = New Teller

Next

Do

For i As Integer = 0 To 99

Dim t As New Threading.Thread(AddressOf
Tellers(i).DoWork)

Threads(i) = t

t.Start()

Next

For i As Integer = 0 To 99

Threads(i).Join()

Next

Dim B2 As Integer = BankInt.Balance

Console.WriteLine("Int Balance " & B2)

Dim B1 As Long = BankLong.Balance

Console.WriteLine("Long Balance " & B1)

Loop

End Sub

End Module



Option Explicit On

Option Strict On

Imports System.Threading

Public Class Teller

Public Sub DoWork()

For i As Integer = 1 To 100000

BankInt.Deposit(50)

BankInt.Withdraw(50)

BankLong.Deposit(50)

BankLong.Withdraw(50)

Next

End Sub

End Class

Option Explicit On

Option Strict On

Imports System.Threading

Public Class BankLong

Private Shared _balance As Long

Public Shared ReadOnly Property Balance() As Long

Get

Return Interlocked.Read(_balance)

End Get

End Property

Public Shared Sub Deposit(ByVal Amount As Long)

Interlocked.Add(_balance, Amount)

End Sub

Public Shared Sub Withdraw(ByVal Amount As Long)

Interlocked.Add(_balance, -Amount)

End Sub

End Class

Public Class BankInt

Private Shared _balance As Integer

Public Shared ReadOnly Property Balance() As Integer

Get

Return _balance

End Get

End Property

Public Shared Sub Deposit(ByVal Amount As Integer)

Interlocked.Add(_balance, Amount)

End Sub

Public Shared Sub Withdraw(ByVal Amount As Integer)

Interlocked.Add(_balance, -Amount)

End Sub

End Class


这篇关于Interlocked.在32位系统上添加不带线程安全线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆