Функция, которая всегда возвращает следующее целое число в последовательности - PullRequest
0 голосов
/ 10 февраля 2012

Мне нужно сверху создать функцию, которая получает следующее целое число в последовательности от 1 до 60. Каждый раз, когда вызывается функция, мне нужно, чтобы она увеличивалась с того, что было последним значением, и возвращала следующее число в качестве результата.Он также не может вернуть одно и то же целое число в 2 последовательных вызовах.Когда счетчик достигает 60, последовательность должна быть сброшена обратно до 1. Я хотел бы, чтобы функция не имела параметров.

Я создал функцию, которая делает это, используя кэш для хранения последнего значения, которое быловернулся, но меня беспокоит, что при одновременных вызовах функции она может работать не так, как я ожидаю, и 2 вызова могут получить одно и то же целое число.

Кэш-память блокирует правильный метод для использования в этом случае или существуеткакой-то другой метод, о котором я не думаю?

Кроме того, застрял с помощью .Net 3.5, и это веб-приложение.


Я только что написал эту функцию на основе использования 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 голосов
/ 10 февраля 2012

Похоже, вы реализуете IEnumerator. Статья MSDN для этого интерфейса - хорошее место для начала. Относительно безопасности потока, статья заявляет:

Перечислитель не имеет эксклюзивного доступа к коллекции; следовательно, перечисление через коллекцию по сути не является потокобезопасной процедурой. Даже когда коллекция синхронизирована, другие потоки могут изменять коллекцию, что приводит к тому, что перечислитель создает исключение. Чтобы гарантировать безопасность потоков во время перечисления, вы можете либо заблокировать коллекцию во время всего перечисления, либо перехватить исключения, возникающие в результате изменений, внесенных другими потоками.

Пример использования блокировки для создания многопоточного IEnumerator см. в этой статье .

Теперь, требует ли ваша потокобезопасность, чтобы каждый поток использовал свой собственный IEnumerator или они совместно используют один? Я думаю, что статья CodeProject, на которую ссылаются, предполагает первую. Последнее может быть затруднено, потому что MoveNext и Current по своей природе являются отдельными операциями. Таким образом, блокировка обоих элементов атомного звучит как вызов дизайна.

К счастью, похоже, что Джон Скит принял этот вызов :)

0 голосов
/ 10 февраля 2012

ASP.net Cache является поточно-ориентированным, но возможно, что два потока одновременно обращаются к одному и тому же объекту.

Я бы рекомендовал посмотреть на класс ConcurrentQueue (Of T) http://msdn.microsoft.com/en-us/library/dd267265.aspx

Параллельная очередь будет блокировать вызовы до тех пор, пока исходный вызов не будет завершен. Кроме того, поскольку каждый раз, когда вы удаляете элемент, это стек, вы просто помещаете его обратно в стек, создавая последовательный цикл.

есть:

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

Конечный модуль

0 голосов
/ 10 февраля 2012

В Java я бы использовал AtomicInteger ... Нашел несколько портов для .Net :

Фрагмент кода Java:

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();
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...