我需要top创建一个函数,它获取1到60序列中的下一个整数。每次调用该函数时,我需要它从最后一个值开始递增并返回下一个数字作为结果。它也不能在2次连续调用中返回相同的整数。当计数达到60时,序列需要重置为1.我希望功能没有参数。
我创建了一个使用缓存执行此操作的函数来存储返回的最后一个值,但是我担心对函数的并发调用它可能无法正常工作,并且2个调用可以获得相同的整数
缓存是否阻止了在此实例中使用的正确方法,还是有其他方法我没有考虑过?
另外,使用.Net 3.5,这是一个Web应用程序。
我刚刚使用SyncLock编写了这个函数。我没看到任何明显的问题吗?我正在使用缓存来保存返回的最后一个值。
Private Shared Function GetNextNumber() As Integer
Dim o As Integer
Dim r As Integer
If Not Cache("NextNumber") Is Nothing Then
o = DirectCast(Cache("NextNumber"), Integer)
Else
Cache.Insert("NextNumber", 1, Nothing, Nothing, Nothing, Caching.CacheItemPriority.NotRemovable, Nothing)
End If
Dim lock As New Object
SyncLock lock
If o = 60 Then
r = 1
Else
r = o + 1
End If
Cache.Insert("NextNumber", r, Nothing, Nothing, Nothing, Caching.CacheItemPriority.NotRemovable, Nothing)
End SyncLock
Return r
End Function
答案 0 :(得分:0)
在java中我会使用AtomicInteger ...找到.Net的一些端口:
Java code snippet:
public class Sequence {
private final AtomicInteger counter;
Sequence(int max) {
counter = new AtomicInteger(0);
this.max = max);
}
public int next() {
counter.compareAndSet(max,0);
return counter.getAndIncrement();
}
}
答案 1 :(得分:0)
听起来你正在实施IEnumerator
。 The MSDN article for that interface是一个开始的好地方。关于线程安全,文章指出:
枚举器没有对集合的独占访问权限;因此,枚举通过集合本质上不是一个线程安全的过程。即使集合是同步的,其他线程仍然可以修改集合,这会导致枚举器抛出异常。要在枚举期间保证线程安全,您可以在整个枚举期间锁定集合,也可以捕获由其他线程所做的更改导致的异常。
有关使用锁定创建线程安全IEnumerator
的示例,请参阅this article。
现在,您的线程安全是否要求每个线程使用自己的IEnumerator
或者它们共享一个?我认为引用的CodeProject文章是假设前者。后者可能很难,因为MoveNext
和Current
在设计上是单独的操作。因此,原子锁定听起来像设计挑战。
幸运的是,看起来Jon Skeet有taken up that challenge:)
答案 2 :(得分:0)
ASP.net缓存是线程安全的,但两个线程可能同时访问同一个对象。
我建议看一下“ConcurrentQueue(Of T)Class”http://msdn.microsoft.com/en-us/library/dd267265.aspx
Concurrent Queue将阻止呼叫,直到原始呼叫完成。另外,因为每次删除项目时它都是一个堆栈,所以只需将其推回到堆栈中即可进行顺序循环。
即:
Module Module1
Private _Stack As New Concurrent.ConcurrentQueue(Of Integer)
Sub main()
For i As Integer = 1 To 60
_Stack.Enqueue(i)
Next
Do While True
Debug.WriteLine(GetNext())
Loop
End Sub
Private Function GetNext() As Nullable(Of Integer)
Dim result As Integer
If _Stack.TryDequeue(result) Then
_Stack.Enqueue(result)
End If
Return result
End Function
结束模块
这就是我在3.5中的表现:
Module Module1
Private _Stack As New Queue(Of Integer)
Sub main()
For i As Integer = 1 To 60
_Stack.Enqueue(i)
Next
Do While True
Debug.WriteLine(GetNext())
Loop
End Sub
Private Function GetNext() As Nullable(Of Integer)
Dim result As Integer
SyncLock _Stack
result = _Stack.Dequeue()
_Stack.Enqueue(result)
End SyncLock
Return result
End Function
结束模块