Как определить критические разделы в C #? - PullRequest
0 голосов
/ 18 сентября 2018

РЕДАКТИРОВАТЬ: Это не то же самое, что сообщение "CRITICAL_SECTION in c #", как это было предложено кем-то еще.Этот пост о том, как определить код, который необходимо выполнить в критическом разделе.Предлагаемый повторяющийся пост спрашивает о том, как использовать Windows OS API для критических разделов.Даже близко не то же самое.

Изучение многопоточности и асинхронного кода.Немного борется с выявлением критических разделов.Не совсем уверен, что является общим и что является исключительным между переключениями контекста.Разница между тем, как обрабатываются типы значений и ссылочные типы.Обрабатывается ли в методе локальная переменная, внешняя переменная и передаваемый параметр.

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

Сначала давайте посмотрим, верны ли некоторые предположения.CS для удобства является «критической секцией».

  1. ++localX должен находиться в CS, поскольку это локальная переменная.int localX = 0 нормально, потому что это атомарно в C #.т. е. поток не будет устанавливать localX обратно в 0 для другого потока, когда он первоначально объявляет переменную.
  2. ++externalX должен находиться в CS, поскольку он является общим ресурсом.И он должен быть объявлен как volatile, иначе поток может воздействовать на кэшированное значение и в результате получится неверный результат.
  3. externalParms.Add( parms[0] ); должен быть в CS, поскольку метод Add не является потокобезопасным, и онэто общий ресурс.Также должен быть объявлен как volatile.
  4. myList[localX] = externalX; должен находиться в CS, так как индексатор не является потокобезопасным и является локальной переменной.

Вопросы

  1. А как насчет кода ADO.NET?
    • using (var command = new SqlCommand(spName, connection)) Нужно ли беспокоиться о потоке, помещающем свой spName в другой поток command объект?
    • command.Parameters.AddRange(parms); Я добавляю значения в коллекцию.Это не потокобезопасно и должно быть в CS?
    • await command.ExecuteNonQueryAsync(); command является локальной переменной.Документация ничего не говорит о том, что метод ExecuteNonQueryAsync() является потокобезопасным.CS или нет CS?
  2. parms[0].Value = rnum; должен быть в CS?

Произвольный код:

int externalX = 10;
List<SqlParameter> externalParms = new List<SqlParameter>();
internal async Task SampleExecuteNonQueryAsync(string spName, SqlParameter[] parms)
{
    int localX = 0;
    List<int> myList = new List<int>() { -1,-1};
    Random rnd = new Random();

    using (var connection = new SqlConnection(_connString))
    {
        await connection.OpenAsync();
        using (var command = new SqlCommand(spName, connection))
        {
            ++localX;
            int rnum = rnd.Next(1, 100);
            parms[0].Value = rnum;

            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.AddRange(parms);
            await command.ExecuteNonQueryAsync();

            ++externalX;                    
        }
    }
    myList[localX] = externalX;
    externalParms.Add( parms[0] );
}

1 Ответ

0 голосов
/ 18 сентября 2018

Я думаю, что вы запутались и переосмыслили вещи.

Любые переменные, основанные на стеке (то есть локальные переменные), являются "для каждого потока", поэтому нет необходимости блокировать что-либо для них, каждый поток будетесть совершенно отдельный.

Если вас беспокоит, что более 1 потока получит доступ к externalParms, используйте одну из коллекций, созданных для этой цели: https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/

...