Чтение и запись коллекций из разных потоков
От: zoom-zoom  
Дата: 22.01.15 20:58
Оценка: :)
День добрый!
Немного запутался с потоками. Делаю следующее:

    static object _object = new object(); 
    private void button1_Click(object sender, EventArgs e) 
    { 
        t1 = new Thread(tr1); 
        t1.Start(); 
        Thread t2 = new Thread(tr2); 
        t2.Start(); 
    }
    private void button2_Click(object sender, EventArgs e) 
    { 
        lock (_object) 
        { 
            MyStruct ms = MyClass.mylist[2]; 
            ms.var1 = 0; 
            MyClass.mylist[2] = ms; 
        } 
    } 
    static void tr1() 
    { 
        while (true) 
        { 
            lock (_object) 
            { 
                MyStruct ms = MyClass.mylist[2]; 
                ms.var2 = 1; 
                MyClass.mylist[2] = ms; 
            } 
            Thread.Sleep(1); 
        } 
    } 
    static void tr2() 
    { 
        while (true) 
        { 
            lock (_object) 
            { 
                MyStruct ms = MyClass.mylist[2]; 
                ms.var2 = 2; 
                MyClass.mylist[2] = ms; 
            } 
            Thread.Sleep(1); 
        } 
    } 
    public static class MyClass 
    { 
        public static SortedList<int,MyStruct> mylist = new SortedList<int,MyStruct>(); 
    } 
    public struct MyStruct 
    { 
        public int var1; 
        public int var2; 
    }


Задача в том, чтобы обновляя в SortedList данные, ничего не потерялось бы и все переменные mylist получили бы нужные значения.
Но есть нюанс в приведенном примере. При работе с lock иногда может зависнуть код в строке с lock в button2_Click. Если убрать lock везде или где-то, то может быть случай, когда запись идет некооректно в mylist из-за прерывания потока и обновления данных в другом потоке. Как можно еще обезопасить, если не lock, чтобы не было зависаний?
Re: Чтение и запись коллекций из разных потоков
От: ZagSer168 Ниоткуда https://u168.ru
Дата: 23.01.15 03:26
Оценка: -1
Можно перенести модификацию mylist из button2_Click в отдельный поток.
Одиночное наследование — это всего лишь частный случай множественного наследования.
Re[2]: Чтение и запись коллекций из разных потоков
От: zoom-zoom  
Дата: 23.01.15 09:52
Оценка:
Здравствуйте, ZagSer168, Вы писали:

ZS>Можно перенести модификацию mylist из button2_Click в отдельный поток.


lock в отельном потоке не зависнет тогда?
Re[3]: Чтение и запись коллекций из разных потоков
От: ZagSer168 Ниоткуда https://u168.ru
Дата: 23.01.15 11:21
Оценка: -1
Зависит или нет не ясно, т.к. порядок входа в lock не предсказуем и зависит от многих причин.

Важно, что главный поток не зависнет.
Одиночное наследование — это всего лишь частный случай множественного наследования.
Re: Чтение и запись коллекций из разных потоков
От: artelk  
Дата: 23.01.15 12:08
Оценка:
Здравствуйте, zoom-zoom, Вы писали:

ZZ>День добрый!

ZZ>Немного запутался с потоками. Делаю следующее:

ZZ>
ZZ>    private void button2_Click(object sender, EventArgs e) 
ZZ>    { 
ZZ>        lock (_object) 
ZZ>        { 
ZZ>            MyStruct ms = MyClass.mylist[2]; 
ZZ>            ms.var1 = 0; 
ZZ>            MyClass.mylist[2] = ms; 
ZZ>        } 
ZZ>    } 
ZZ>



ZZ>Задача в том, чтобы обновляя в SortedList данные, ничего не потерялось бы и все переменные mylist получили бы нужные значения.

ZZ>Но есть нюанс в приведенном примере. При работе с lock иногда может зависнуть код в строке с lock в button2_Click. Если убрать lock везде или где-то, то может быть случай, когда запись идет некооректно в mylist из-за прерывания потока и обновления данных в другом потоке. Как можно еще обезопасить, если не lock, чтобы не было зависаний?

В button2_Click можно сделать Monitor.TryEnter(_object) и, если удалось, выполнить эти три строчки прямо по месту и потом сделать Monitor.Exit(_object).
Если блокировку захватить не удалось — запустить отдельный поток (или добавить задание в ThreadPool) и уже оттуда сделать все с обычным локом.
Отредактировано 23.01.2015 12:10 artelk . Предыдущая версия .
Re: Чтение и запись коллекций из разных потоков
От: abibok  
Дата: 23.01.15 16:43
Оценка:
https://msdn.microsoft.com/en-us/library/dn385366%28v=vs.110%29.aspx
Re[2]: Чтение и запись коллекций из разных потоков
От: zoom-zoom  
Дата: 23.01.15 21:57
Оценка:
Здравствуйте, artelk, Вы писали:

A>Здравствуйте, zoom-zoom, Вы писали:


ZZ>>День добрый!

ZZ>>Немного запутался с потоками. Делаю следующее:

ZZ>>
ZZ>>    private void button2_Click(object sender, EventArgs e) 
ZZ>>    { 
ZZ>>        lock (_object) 
ZZ>>        { 
ZZ>>            MyStruct ms = MyClass.mylist[2]; 
ZZ>>            ms.var1 = 0; 
ZZ>>            MyClass.mylist[2] = ms; 
ZZ>>        } 
ZZ>>    } 
ZZ>>



ZZ>>Задача в том, чтобы обновляя в SortedList данные, ничего не потерялось бы и все переменные mylist получили бы нужные значения.

ZZ>>Но есть нюанс в приведенном примере. При работе с lock иногда может зависнуть код в строке с lock в button2_Click. Если убрать lock везде или где-то, то может быть случай, когда запись идет некооректно в mylist из-за прерывания потока и обновления данных в другом потоке. Как можно еще обезопасить, если не lock, чтобы не было зависаний?

A>В button2_Click можно сделать Monitor.TryEnter(_object) и, если удалось, выполнить эти три строчки прямо по месту и потом сделать Monitor.Exit(_object).

A>Если блокировку захватить не удалось — запустить отдельный поток (или добавить задание в ThreadPool) и уже оттуда сделать все с обычным локом.


lock и Monitor, по сути, одно и то же. Пишут, что локер предпочтительнее использовать. Но я пытаюсь отказаться от него, разделить массивы, чтобы не было работы одновременной с ним.
Re[2]: Чтение и запись коллекций из разных потоков
От: zoom-zoom  
Дата: 23.01.15 21:57
Оценка:
Здравствуйте, abibok, Вы писали:

A>https://msdn.microsoft.com/en-us/library/dn385366%28v=vs.110%29.aspx


Интересная штука, не знал о такой, поизучаю, спасибо!
Re: Чтение и запись коллекций из разных потоков
От: Lexey Россия  
Дата: 27.01.15 13:17
Оценка:
Здравствуйте, zoom-zoom, Вы писали:

ZZ>Задача в том, чтобы обновляя в SortedList данные, ничего не потерялось бы и все переменные mylist получили бы нужные значения.

ZZ>Но есть нюанс в приведенном примере. При работе с lock иногда может зависнуть код в строке с lock в button2_Click. Если убрать lock везде или где-то, то может быть случай, когда запись идет некооректно в mylist из-за прерывания потока и обновления данных в другом потоке. Как можно еще обезопасить, если не lock, чтобы не было зависаний?

1) Начать нужно с вопроса о нужности SortedList. Вполне возможно, что его можно замнить на Dictionary или ConcurrentDictionary или еще что-то (в данном примере он, очевидно, нафиг не нужен).
2) Замена struct на class позволяет убрать лишнюю операцию обновления, модифицируя напрямую поля класса.
3) Потоки со слипами — это адский ад. Наверняка спокойно заменяются таймерами или ожиданием на ивенте, на крайняк.
"Будь достоин победы" (c) 8th Wizard's rule.
Re[2]: Чтение и запись коллекций из разных потоков
От: zoom-zoom  
Дата: 27.01.15 16:47
Оценка: :)
Здравствуйте, Lexey, Вы писали:

L>Здравствуйте, zoom-zoom, Вы писали:


ZZ>>Задача в том, чтобы обновляя в SortedList данные, ничего не потерялось бы и все переменные mylist получили бы нужные значения.

ZZ>>Но есть нюанс в приведенном примере. При работе с lock иногда может зависнуть код в строке с lock в button2_Click. Если убрать lock везде или где-то, то может быть случай, когда запись идет некооректно в mylist из-за прерывания потока и обновления данных в другом потоке. Как можно еще обезопасить, если не lock, чтобы не было зависаний?

L>1) Начать нужно с вопроса о нужности SortedList. Вполне возможно, что его можно замнить на Dictionary или ConcurrentDictionary или еще что-то (в данном примере он, очевидно, нафиг не нужен).

L>2) Замена struct на class позволяет убрать лишнюю операцию обновления, модифицируя напрямую поля класса.
L>3) Потоки со слипами — это адский ад. Наверняка спокойно заменяются таймерами или ожиданием на ивенте, на крайняк.

1. Был нужен SortedList для удобства дальнейшего пользования.
2. привык к структурам
3. System.Timers можно, но с while быстрее, иногда слипы убираю, загружая ЦП по полной. System.Threading для GUI не подходит, отключается при первом же клике по форме. Может есть еще варианты, не раскопал пока.
Re[3]: Чтение и запись коллекций из разных потоков
От: Lexey Россия  
Дата: 28.01.15 08:43
Оценка:
Здравствуйте, zoom-zoom, Вы писали:

ZZ>1. Был нужен SortedList для удобства дальнейшего пользования.


А можно реальный пример, в котором может возникнуть это удобство?

ZZ>2. привык к структурам


Тут вопрос в эффективности, а не в привычке.

ZZ>3. System.Timers можно, но с while быстрее, иногда слипы убираю, загружая ЦП по полной. System.Threading для GUI не подходит, отключается при первом же клике по форме. Может есть еще варианты, не раскопал пока.


System.Threading.Timer нормально можно использовать с UI. Просты ты его готовить не умеешь, видимо.
Опять же, интересно было бы узнать, что это за задача такая, в которой нужно постоянно крутить циклы.
"Будь достоин победы" (c) 8th Wizard's rule.
Re[4]: Чтение и запись коллекций из разных потоков
От: zoom-zoom  
Дата: 28.01.15 11:46
Оценка: -1
Здравствуйте, Lexey, Вы писали:

L>Здравствуйте, zoom-zoom, Вы писали:


ZZ>>1. Был нужен SortedList для удобства дальнейшего пользования.


L>А можно реальный пример, в котором может возникнуть это удобство?


В SortedList удобнее заменять данные, быстрее читать из него по индексу.

ZZ>>2. привык к структурам


L>Тут вопрос в эффективности, а не в привычке.


Это спорный вопрос. Структура, например, избавляет меня от проверок на null. (struct VS class: http://www.calabonga.net/blog/post/56)

ZZ>>3. System.Timers можно, но с while быстрее, иногда слипы убираю, загружая ЦП по полной. System.Threading для GUI не подходит, отключается при первом же клике по форме. Может есть еще варианты, не раскопал пока.


L>System.Threading.Timer нормально можно использовать с UI. Просты ты его готовить не умеешь, видимо.

L>Опять же, интересно было бы узнать, что это за задача такая, в которой нужно постоянно крутить циклы.

Не могу найти нормального описания для работы System.Threading.Timer с UI.
А задача такая, что нужно делать некий процессинг постоянно, который запускает callback.
Re[5]: Чтение и запись коллекций из разных потоков
От: Lexey Россия  
Дата: 28.01.15 19:26
Оценка:
Здравствуйте, zoom-zoom, Вы писали:

ZZ>>>1. Был нужен SortedList для удобства дальнейшего пользования.


L>>А можно реальный пример, в котором может возникнуть это удобство?


ZZ>В SortedList удобнее заменять данные, быстрее читать из него по индексу.


Серьезно? И чем же эти операции удобнее, чем у Dictionary? Тормознее — да, но удобнее?

ZZ>>>2. привык к структурам


L>>Тут вопрос в эффективности, а не в привычке.


ZZ>Это спорный вопрос. Структура, например, избавляет меня от проверок на null. (struct VS class: http://www.calabonga.net/blog/post/56)


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

ZZ>>>3. System.Timers можно, но с while быстрее, иногда слипы убираю, загружая ЦП по полной. System.Threading для GUI не подходит, отключается при первом же клике по форме. Может есть еще варианты, не раскопал пока.


L>>System.Threading.Timer нормально можно использовать с UI. Просты ты его готовить не умеешь, видимо.

L>>Опять же, интересно было бы узнать, что это за задача такая, в которой нужно постоянно крутить циклы.

ZZ>Не могу найти нормального описания для работы System.Threading.Timer с UI.


А зачем его искать? Threading.Timer с UI вообще никак не связан. Единственный момент, который нужно помнить, используя его с UIем, — то, что он работает на потоках пула, и модификацию всяких контролов, если она нужна, придется делать через Invoke. Все остальное можно прочитать в MSDNе.

ZZ>А задача такая, что нужно делать некий процессинг постоянно, который запускает callback.


И как это соотносится с исходным примером с кнопкой? В такой формулировке задача не имеет никакого практического смысла.
"Будь достоин победы" (c) 8th Wizard's rule.
Re[6]: Чтение и запись коллекций из разных потоков
От: zoom-zoom  
Дата: 28.01.15 20:26
Оценка: :)
Здравствуйте, Lexey, Вы писали:

L>Здравствуйте, zoom-zoom, Вы писали:


ZZ>>>>1. Был нужен SortedList для удобства дальнейшего пользования.


L>>>А можно реальный пример, в котором может возникнуть это удобство?


ZZ>>В SortedList удобнее заменять данные, быстрее читать из него по индексу.


L>Серьезно? И чем же эти операции удобнее, чем у Dictionary? Тормознее — да, но удобнее?


Изуча момент, возможно исправлю на Dictionary.

ZZ>>>>2. привык к структурам


L>>>Тут вопрос в эффективности, а не в привычке.


ZZ>>Это спорный вопрос. Структура, например, избавляет меня от проверок на null. (struct VS class: http://www.calabonga.net/blog/post/56)


L>В данном случае он бесспорный. Проверка на null тут может быть нужна (а может и вообще быть не нужна) только перед вставкой в контейнер, она прекрасно делается не под блокировкой и почти ничего не стоит. А вот за мнимое удобство приходится платить дополнительной "дорогой" операцией вставки в контейнер, выполняемой под блокировкой.

L>Про то, что неинициализированная структура — это гораздо большая засада, чем null, наверное и говорить не стоит.

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

ZZ>>>>3. System.Timers можно, но с while быстрее, иногда слипы убираю, загружая ЦП по полной. System.Threading для GUI не подходит, отключается при первом же клике по форме. Может есть еще варианты, не раскопал пока.


L>>>System.Threading.Timer нормально можно использовать с UI. Просты ты его готовить не умеешь, видимо.

L>>>Опять же, интересно было бы узнать, что это за задача такая, в которой нужно постоянно крутить циклы.

ZZ>>Не могу найти нормального описания для работы System.Threading.Timer с UI.


L>А зачем его искать? Threading.Timer с UI вообще никак не связан. Единственный момент, который нужно помнить, используя его с UIем, — то, что он работает на потоках пула, и модификацию всяких контролов, если она нужна, придется делать через Invoke. Все остальное можно прочитать в MSDNе.


c Threading.Timer разобрался, думал глючит или другими потоками убивается где-то, а я таймер объявил локально и он уничтожался поэтому очень быстро. Теперь надо while убрать и все... Этот вопрос теперь закрыт!!!
Спасибо!!! Буду дальше набираться опыта.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.