Если бы я был Вами, то я создал бы отдельный класс, который инкапсулирует набор данных и содержит всю логику, вовлеченную в обработку записей набора данных. Этот класс мог быть повторяемым (ответьте каждому). Тогда я передал бы экземпляр этого класса к представлению и использовал бы только его методы там.
Во-первых, многопоточность - дело сложное ;-p
Да, несмотря на все слухи об обратном, требуется для либо использования lock
или volatile
(но не оба сразу) при доступе к bool
из нескольких потоков.
Для простых типов и доступа, таких как флаг выхода ( bool
), тогда volatile
будет достаточно - это гарантирует, что потоки не кэшируют значение в своих регистрах (что означает: один из потоков никогда не видит обновления).
Для больших значений (где атомарность является проблемой), или если вы хотите синхронизировать последовательность операций (типичный пример - «если не существует, добавьте» доступ к словарю), блокировка
более универсальна. Это действует как барьер памяти, так что по-прежнему обеспечивает безопасность потоков, но предоставляет другие функции, такие как импульс / ожидание. Обратите внимание, что вы не должны использовать блокировку
для типа значения или строки
; ни Тип
или это
; лучший вариант - иметь собственный блокирующий объект в качестве поля ( readonly object syncLock = new object ();
) и заблокировать его.
Пример того, насколько сильно он ломается (т. е. бесконечный цикл ), если вы не синхронизируете - см. здесь .
Чтобы охватить несколько программ, примитив ОС, такой как Mutex
или * ResetEvent
, также может быть полезен , но это перебор для одного exe.
Тип
или это
; лучший вариант - иметь собственный блокирующий объект в качестве поля ( readonly object syncLock = new object ();
) и заблокировать его.
Пример того, насколько сильно он ломается (т. е. бесконечный цикл ), если вы не синхронизируете - см. здесь .
Чтобы охватить несколько программ, примитив ОС, такой как Mutex
или * ResetEvent
, также может быть полезен , но это перебор для одного exe.
Тип
или это
; лучший вариант - иметь собственный блокирующий объект в качестве поля ( readonly object syncLock = new object ();
) и заблокировать его.
Пример того, насколько сильно он ломается (т. е. бесконечный цикл ), если вы не синхронизируете - см. здесь .
Чтобы охватить несколько программ, примитив ОС, такой как Mutex
или * ResetEvent
, также может быть полезен , но это перебор для одного exe.
Блокировка не требуется, потому что у вас есть сценарий с одним записывающим устройством, а логическое поле представляет собой простую структуру без риска повреждения состояния (, хотя можно было получить логическое значение, которое не является ни ложным, ни истинным ). Но вы должны пометить поле как volatile
, чтобы компилятор не выполнял некоторые оптимизации. Без модификатора volatile
компилятор мог бы кэшировать значение в регистре во время выполнения вашего цикла в рабочем потоке, и, в свою очередь, цикл никогда не распознал бы измененное значение. Эта статья MSDN ( Как:
Хотя существует необходимость в блокировке, блокировка будет иметь тот же эффект, что и пометка поля изменчивым
.
Найдите Interlocked.Exchange () . Он очень быстро копирует в локальную переменную, которую можно использовать для сравнения. Это быстрее, чем lock ().
_cancelled
must be volatile
. (if you don't choose to lock)
If one thread changes the value of _cancelled
, other threads might not see the updated result.
Also, I think the read/write operations of _cancelled
are atomic:
Section 12.6.6 of the CLI spec states: "Соответствующий интерфейс командной строки должен гарантировать, что доступ для чтения и записи к правильному выровненные ячейки памяти не больше чем исходный размер слова атомарен когда все записи обращаются к location are the same size."
For thread synchronization, it's recommended that you use one of the EventWaitHandle
classes, such as ManualResetEvent
. While it's marginally simpler to employ a simple boolean flag as you do here (and yes, you'd want to mark it as volatile
), IMO it's better to get into the practice of using the threading tools. For your purposes, you'd do something like this...
private System.Threading.ManualResetEvent threadStop;
void StartThread()
{
// do your setup
// instantiate it unset
threadStop = new System.Threading.ManualResetEvent(false);
// start the thread
}
In your thread..
while(!threadStop.WaitOne(0) && !operationComplete)
{
// work
}
Then in the GUI to cancel...
threadStop.Set();