Что такое класс потоков, если я просто хочу протестировать и установить флаг безопасным способом? - PullRequest
5 голосов
/ 15 января 2010

Я просто хочу сделать простой, хотя и поточно-безопасный, логический тест (и установить) так:

if(myBoolean==false)   //should not lock/wait!
{ 
     myBoolean=true;
     .....
}
else
{
     ....
}

Я учел следующее (хотя, возможно, неправильно, поэтому, пожалуйста, поправьте меня там, где я неправильно понял)

  • использование конструкции Lock {if (myBoolean) ...} кажется излишним способом сделать это. Кроме того, он также блокирует поток, ожидая освобождения блокировки. Я не хочу этого.
  • Класс AutoResetEvent имеет концепцию логического состояния, но он используется для сигнализации другого потока, который ожидает. Так что не актуально в моем случае
  • В семафорном классе есть понятие счетчика ссылок (возможно, для ограничения количества доступа к ресурсу?). Так что, вероятно, не то, что я после.
  • Mutex класс. Насколько я понял, это тот же принцип, что и примитив Lock

Кто-нибудь имеет представление, что такое класс / конструкция, чтобы сделать это эффективным образом?

Ответы [ 6 ]

8 голосов
/ 15 января 2010
6 голосов
/ 15 января 2010

Ответ (Intelocked.CompareExchange) уже дан, но вот мой пример использования:

private int _isDisposing;

public bool IsDisposing
{
    get
    {
        return this._isDisposing != 0;
    }
}

public void Dispose()
{
    // Side note: I may want to `return` instead of `throw`
    if (Interlocked.CompareExchange(ref _isDisposing, 1, 0) != 0)
        throw new InvalidOperationException("Dispose was recursively called.");

    try
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    finally
    {
        _isDisposing = 0;
    }
}
2 голосов
/ 15 января 2010

Ваш вопрос несколько двусмысленный, но вы, вероятно, ищете класс Interlocked.

РЕДАКТИРОВАТЬ : Вы ищете Interlocked.CompareExchange.

1 голос
/ 21 марта 2017

Для коллекций "Test and Add" я использую

        /// <summary>
    /// If h contains v then return true, else add v to h and return false.
    /// Thread safe on h.
    /// </summary>
    /// <param name="h"></param>
    /// <param name="v"></param>
    /// <returns></returns>
    bool TestAndAdd(HashSet<string> h, string v)
    {
        lock(h)
        {
            if(h.Contains(v))
            {
                return true;
            }
            h.Add(v);
            return false;
        }
    }

Тогда я могу проверить и установить как ..

    if (!TestAndAdd(usedCodes, mc.code))
1 голос
/ 15 января 2010

Чтобы выполнить потокобезопасный тест и установить работу, код должен блокировать другие потоки. Чтобы избежать ненужной блокировки, вы можете использовать шаблон test-and-test-set-set:

if (something) {
   lock(_sync) {
      if (something) {
         something = false;
         ...
      }
   }
}

Второй тест необходим, чтобы убедиться, что какой-то другой поток не изменил значение между первым тестом и блокировкой.

0 голосов
/ 27 декабря 2017

У меня была одна и та же проблема много раз, и я не думаю, что могу иметь в виду, что последний аргумент Interlocked.CompareAndChange () является сравнением. Вот что я придумал.

using System.Threading;

public class AtomicFlag
{
    public const int SETVALUE = 1;
    public const int RESETVALUE = 0;

    /// <summary>
    /// Represents the current state of the flag.
    /// 0 means false (or reset).
    /// 1 means true (or set).
    /// </summary>
    private int Value;

    /// <summary>
    /// Creates an atomicflag with the specified default value.
    /// </summary>
    /// <param name="initialValue">AtomicFlag.SETVALUE or 
    /// AtomicFlag.RESETVALUE. Defaults to RESETVALUE.</param>
    public AtomicFlag(int initialValue = RESETVALUE)
    {
        Guard.AgainstUnsupportedValues<int>(initialValue, "initialValue",
           new int[] { SETVALUE, RESETVALUE });
        Value = initialValue;
    }


    public void Set()
    {
        Value = SETVALUE;
    }

    public void Reset()
    {
        Value = RESETVALUE;
    }


    public bool TestAndSet()
    {
        // Use Interlocked to test if the current value is RESETVALUE,
        // return true and set value to SETVALUE.
        //
        // From Interlocked.CompareExchange help:
        // public static int CompareExchange(
        //    ref int location1,
        //    int value,
        //    int comparand
        // )
        // where
        //  location1: The destination, whose value is compared with 
        //             comparand and possibly replaced.
        //  value:     The value that replaces the destination value if the
        //             comparison results in equality.
        //  comparand: The value that is compared to the value at
        //             location1. 
        return (RESETVALUE == Interlocked.CompareExchange(
            ref Value, SETVALUE, RESETVALUE));
    }

    public bool TestAndReset()
    {
        // If the current value is SETVALUE, return true and change value 
        // to RESETVALUE.
        return (SETVALUE ==
            Interlocked.CompareExchange(ref Value, RESETVALUE, SETVALUE));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...