始终返回序列中下一个整数的函数

时间:2012-02-10 13:58:05

标签: .net vb.net caching

我需要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

3 个答案:

答案 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)

听起来你正在实施IEnumeratorThe MSDN article for that interface是一个开始的好地方。关于线程安全,文章指出:

  

枚举器没有对集合的独占访问权限;因此,枚举通过集合本质上不是一个线程安全的过程。即使集合是同步的,其他线程仍然可以修改集合,这会导致枚举器抛出异常。要在枚举期间保证线程安全,您可以在整个枚举期间锁定集合,也可以捕获由其他线程所做的更改导致的异常。

有关使用锁定创建线程安全IEnumerator的示例,请参阅this article

现在,您的线程安全是否要求每个线程使用自己的IEnumerator或者它们共享一个?我认为引用的CodeProject文章是假设前者。后者可能很难,因为MoveNextCurrent在设计上是单独的操作。因此,原子锁定听起来像设计挑战。

幸运的是,看起来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

结束模块