.Net Критические области в потоке не работают должным образом - PullRequest
3 голосов
/ 03 февраля 2010

Я пытаюсь запустить пример кода (очень простой), включающий многопоточность и критические области.

Вот мой код:

public static void DoCriticalWork(object o)
        {
            SomeClass instance = o as SomeClass;

            Thread.BeginCriticalRegion();
            instance.IsValid = true;
            Thread.Sleep(2);
            instance.IsComplete = true;
            Thread.EndCriticalRegion();

            instance.Print();
        }

И я называю это следующим образом:

private static void CriticalHandled()
        {
            SomeClass instance = new SomeClass();
            ParameterizedThreadStart operation = new ParameterizedThreadStart(CriticalRegion.DoCriticalWork);
            Thread t = new Thread(operation);
            Console.WriteLine("Start thread");
            t.Start(instance);
            Thread.Sleep(1);
            Console.WriteLine("Abort thread");
            t.Abort();

            Console.WriteLine("In main");
            instance.Print();
        }

Тем не менее, вывод, который я получаю:

**

Start thread
Abort thread
In main
IsValid: True
IsComplete: False

**

Поскольку критическая область определена, IsComplete должно быть истинным, а не ложным.

Может кто-нибудь объяснить, почему он не работает?

Вот SomeClass для справки:

public class SomeClass
    {
        private bool _isValid;

        public bool IsValid
        {
            get { return _isValid; }
            set { _isValid = value; }
        }

        private bool _isComplete;

        public bool IsComplete
        {
            get { return _isComplete; }
            set { _isComplete = value; }
        }

        public void Print()
        {
            Console.WriteLine("IsValid: {0}", IsValid);
            Console.WriteLine("IsComplete: {0}", IsComplete);
            Console.WriteLine();
        }
    }

Редактировать

Expln из примечаний MCTS: Идея, стоящая за критической областью, заключается в предоставлении области кода, которая должна выполняться, как если бы она была одной строкой. Любая попытка прервать поток, пока он находится в критической области, придется ждать до завершения критической области. В этот момент поток будет прерван, создав исключение ThreadAbortException. Разница между резьбой с критической областью и без нее показана на следующем рисунке:

Критический регион http://www.freeimagehosting.net/uploads/9dd3bb5445.gif

Ответы [ 3 ]

7 голосов
/ 03 февраля 2010

Thread.BeginCriticalRegion не предотвращает прерывание потока. Я полагаю, что он используется для уведомления среды выполнения о том, что если поток прерывается в критическом разделе, не всегда безопасно продолжать работу приложения / домена приложения.

Документы MSDN имеют более полное объяснение: http://msdn.microsoft.com/en-us/library/system.threading.thread.begincriticalregion.aspx

1 голос
/ 03 февраля 2010

Это проблема времени сна.Просто увеличьте разрыв между двумя сновидениями, и вы получите ответ.

Существует два потока: основной поток и поток, выполняющий критическую работу.Теперь, когда вызывается прерывание, поток 't' будет прерываться мгновенно, даже если он не завершил критическую область.

Теперь, когда вы отправили основной поток в спящий режим на 2 мс, а поток t на 1 мс, иногда t завершит критический раздел, а иногда - нет.Вот почему значение IsComplete иногда равно false, а иногда true.

Теперь просто отправьте основной поток в спящий режим на 100 мс, и вы обнаружите, что IsComplete всегда имеет значение true.И наоборот, отправьте поток "t" в спящий режим на 100 мс, и вы обнаружите, что IsComplete всегда ложно.

РЕДАКТИРОВАТЬ

ОТ MSDN

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

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

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


From CLR Inside Out: написание надежного кода

Состояние коррупции Есть три корзины, которыегосударственная коррупция может попасть в.Первый - это локальное состояние, которое включает локальные переменные и объекты кучи, которые используются только определенным потоком.Второе - это общее состояние, которое включает в себя все, что совместно используется потоками внутри домена приложения, например объекты, хранящиеся в статических переменных.Кэши часто попадают в эту категорию.Третий - это общие для всего процесса, для всей машины и общие для нескольких компьютеров состояния: в этот лагерь попадают менеджеры файлов, сокетов, разделяемой памяти и распределенных блокировок.

Количество состояний, которое может быть поврежденоАсинхронное исключение - это максимальное количество состояний, которое поток в настоящее время изменяет.Если поток выделяет несколько временных объектов и не предоставляет их другим потокам, только эти временные объекты могут быть повреждены. Но если поток пишет в общее состояние, этот общий ресурс может быть поврежден, и другие потоки могут потенциально столкнуться с этим поврежденным состоянием.Вы не должны допустить этого.В этом случае вы прерываете все другие потоки в Домене приложений, а затем выгружаете Домен приложений .Таким образом, асинхронное исключение переходит в домен приложений, вызывая его выгрузку и гарантируя, что любое потенциально поврежденное состояние будет отброшено.Для транзакционного хранилища, такого как база данных, эта переработка домена приложений обеспечивает устойчивость к повреждению локального и общего состояния.

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

0 голосов
/ 03 февраля 2010

Хорошим решением является инкапсуляция кода из DoCriticalWork() с


try { ... } catch(ThreadAbortedException) {...}


, где вы должны действовать, как вы хотите (возможно, установить IsComplete = true?)

Вы можете прочитать больше о ThreadAbortException и обязательно проверить Thread.ResetAbort и использование блока finally для этого случая.

Как Энди упоминается и цитируется с Thread.BeginCriticalRegion :

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

...