Особенности использования стандартных lock'ов для многопотока

evgen_po

Client
Регистрация
27.08.2013
Сообщения
847
Благодарностей
528
Баллы
93
  • Спасибо
Реакции: shtift

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
они не могут быть потокобезопасными, потому что их логика такого не позволяет. Например, чтобы взять строку с удалением, нужно отдельно взять, отдельно удалить. 2 действия. Если бы был отдельный метод, включающий в себя эти 2 действия, тогда он мог бы быть потокобезопасным
Тут ты прав по той причине, что потокобезопасными коллекциями не могут быть листы, так как структура таких коллекций должна поддерживать добавление/извлечение элемента только с начала или с конца (ConcurrenQueue<T>, ConcurrenStack<T>, BlockingCollection<T>), поэтому коллекции в зеннопостере по дефолту не потокобезопасные, если говорить о коде
 
  • Спасибо
Реакции: LaGir

LaGir

Client
Регистрация
01.10.2015
Сообщения
211
Благодарностей
852
Баллы
93
если добавлять несколько проектов в ЗП из одного шаблона - статик переменные общего кода для них будут общие
Интересный момент, не знал - не приходилось использовать их в таких случаях. Благодарю, поковыряю этот момент подробнее и после конкурса добавлю.

Не пойму откуда вы взяли, что нужно вообще пользоваться этими объектами? Поискал в документации и не встретил упоминания, что в шаблонах нужно синхронизировать через них.
Сдается мне, что они созданы исключительно для внутренней логики ZP. Т.е. пока вся статья выглядит так, что вы изначально пользуетесь тем, чем не стоит, а затем поясняете какие из этого проблемы вытекают.
В том и дело, что почти в каждом сниппете на форуме с локами - используются именно эти объекты. Представители ZennoLab в ответах на форуме так же замечены в неоднократном их использовании в примерах кода. Пруф - поиск по форуму. Соответственно, большая часть пользователей Zenno, кто использует локи (найдя нужный для себя сниппет на форуме) - используют именно эти стандартные объекты.
Плюс, не помню, чтобы кто-то на форуме публиковал сниппеты с другими объектами. Вроде только @amyboose где-то писал, что использует сам ресурс в качестве объекта для лока, если память не изменяет.
Про сам ресурс в качестве объекта для лока - согласен, точно стоило написать, тупо забыл. :-)
 
  • Спасибо
Реакции: Dimionix и shtift

Tsuk15

Client
Регистрация
25.04.2017
Сообщения
102
Благодарностей
40
Баллы
28
Именно таких бы статей по больше в конкурсе... Спасибо!
 
  • Спасибо
Реакции: LaGir

Protey

Client
Регистрация
09.01.2016
Сообщения
208
Благодарностей
29
Баллы
28
Для популярных типов внешних ресурсов в ZennoPoster предусмотрено три объекта синхронизации, которые в C#-коде указываются в круглых скобках после lock:
SyncObjects.ListSyncer - для списков
SyncObjects.TableSyncer - для таблиц
SyncObjects.InputSyncer - для буфера обмена
Скажите, а есть способ лочить когда используешь БД MySQL?
 

LaGir

Client
Регистрация
01.10.2015
Сообщения
211
Благодарностей
852
Баллы
93
  • Спасибо
Реакции: Protey

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
Попробовал работать таким методом.

В общем коде добавил строчку:
C#:
public static object SyncObject_accounts = new object();
После чего построил примерно такой фрагмент кода, который берет имена файлов, и проверяет есть ли файл или нет.
Если есть добавляет туда текст.
Если нет - создает, после чего также добавляет текст.

C#:
// Имя файлов
string[] files = { @"keywords_3.txt", @"keywords_2.txt", @"keywords_1.txt"};
// Формирую путь к файлам
string path = string.Format(@"{0}\{1}", project.Directory, @"data");

// Проверяю есть ли папка - если нет - создаю
if (!Directory.Exists(path)) Directory.CreateDirectory(path);

// Беру имя каждого файла по очереди
foreach (string file in files) {
    lock (CommonCode.SyncObject_accounts){
        // Проверяю существование файла
        if(!File.Exists(string.Format(@"{0}\{1}", path, file))) {
            // Если файл не найден - создаю
            File.Create(string.Format(@"{0}\{1}", path, file));
        }
        // Если файл найден или создан - добавляю в файл текст
        File.WriteAllText(string.Format(@"{0}\{1}", path, file), "текст", Encoding.UTF8);
    }
}
В результате, ошибка в логе.
Код:
06:12:02    Выполнение действия CSharp OwnCode Процесс не может получить доступ к файлу "D:\data\keywords_3.txt", так как этот файл используется другим процессом.
Вопрос, что я делаю не так?
Или, данный способ не распространяется на работу с файлами?
 

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 856
Баллы
113
Или, данный способ не распространяется на работу с файлами?
Распространяется, но скорее всего лучше использовать какой-нибудь StreamWriter, где явно будет закрытие файла. Я точно не берусь утверждать, но ощущение, что где-то остается работа с файлом. Далее он как список не используется ведь?
 
  • Спасибо
Реакции: BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
Распространяется, но скорее всего лучше использовать какой-нибудь StreamWriter, где явно будет закрытие файла. Я точно не берусь утверждать, но ощущение, что где-то остается работа с файлом. Далее он как список не используется ведь?
Нет, именно в этом виде который я привел в своем сообщении работает без каких либо дополнительных списков.
Имен файлов может быть например 1000.
И постоянно привязывать/отвязывать списки - не удобно.
Подумал, что раз тема есть о работе локов, то должно все работать корректно.
Но, в результате вижу, что не работает - иначе бы данная ошибка не появлялась (и это в одном потоке - а в многопотоке вообще будет ошибка на ошибке).
Получается, что создание этого объекта который должен был бы лочить файл не решает проблему...

Как тогда работать таким образом с файлами (используя File.Create и File.WriteAllText).
Видел, что можно использовать StreamWriter, но думал, что и File.Create и File.WriteAllText должны как-то освобождать ресурсы.
Может нужно что-то типа Dispose () использовать для освобождения файла?
 

one

Client
Регистрация
22.09.2015
Сообщения
6 793
Благодарностей
1 264
Баллы
113
А это убийственный глюк у зенки при работе с файлами. Я пытался найти решение под один шаблон но так и не нашел и уже не помню как вышел из ситуации. Попробуй после получения ошибки, через 2-3 сек. запустить по новой операцию обращения к файлу. Думаю удевишся. )
 
  • Спасибо
Реакции: orka13 и BAZAg

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
А это убийственный глюк у зенки при работе с файлами. Я пытался найти решение под один шаблон но так и не нашел и уже не помню как вышел из ситуации. Попробуй после получения ошибки, через 2-3 сек. запустить по новой операцию обращения к файлу. Думаю удевишся. )
Через 2-3 секунды выполняется успешно.
Потом последующий запуск - обратно ошибка.
Это для меня не жизненно важно, просто хотелось бы разобраться один раз как правильно работать с файлами в многопотоке.
Ведь с картинками/каптчей возможно такие же велосипеды...
 

one

Client
Регистрация
22.09.2015
Сообщения
6 793
Благодарностей
1 264
Баллы
113
Через 2-3 секунды выполняется успешно.
Потом последующий запуск - обратно ошибка.
Мистика, не правда ли? :-)
Да, разобраться не мешало бы и решить проблему. Не знаешь когда столкнешься с ней повторно и в каком месте.
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
Мистика, не правда ли? :-)
Да, разобраться не мешало бы и решить проблему. Не знаешь когда столкнешься с ней повторно и в каком месте.
Одел File.Create в using и заработало :-)
Рабочий пример выглядит так.
Осталось еще в многопотоке проверить и определиться нужен ли этот объект синхронизации или не нужен.

C#:
// Имя файлов
string[] files = { @"keywords_3.txt", @"keywords_2.txt", @"keywords_1.txt"};
// Формирую путь к файлам
string path = string.Format(@"{0}\{1}", project.Directory, @"data");

// Проверяю есть ли папка - если нет - создаю
if (!Directory.Exists(path)) Directory.CreateDirectory(path);

// Беру имя каждого файла по очереди
foreach (string file in files) {   
        // Проверяю существование файла
        if(!File.Exists(string.Format(@"{0}\{1}", path, file)) {
            // Если файл не найден - создаю
          //File.Create(string.Format(@"{0}\{1}", path, file));
            using ( File.Create(string.Format(@"{0}\{1}", path, file))) {};
        }
        // Если файл найден или создан - добавляю в файл текст
    File.WriteAllText(string.Format(@"{0}\{1}", path, file), "текст", Encoding.UTF8);
}
 
  • Спасибо
Реакции: Nike59 и one

Lord_Alfred

Client
Регистрация
09.10.2015
Сообщения
3 916
Благодарностей
3 856
Баллы
113
Одел File.Create в using и заработало :-)
Интересно) Что-то я даже не задумывался о таком "финте ушами". Расскажи потом как в многопотоке будет, если 1 и тот же файл кучей потоков обрабатывать таким способом (особенно интересует File.WriteAllText)
 

doc

Client
Регистрация
30.03.2012
Сообщения
8 605
Благодарностей
4 596
Баллы
113
Одел File.Create в using и заработало :-)
Рабочий пример выглядит так.
Осталось еще в многопотоке проверить и определиться нужен ли этот объект синхронизации или не нужен.

C#:
// Имя файлов
string[] files = { @"keywords_3.txt", @"keywords_2.txt", @"keywords_1.txt"};
// Формирую путь к файлам
string path = string.Format(@"{0}\{1}", project.Directory, @"data");

// Проверяю есть ли папка - если нет - создаю
if (!Directory.Exists(path)) Directory.CreateDirectory(path);

// Беру имя каждого файла по очереди
foreach (string file in files) {  
        // Проверяю существование файла
        if(!File.Exists(string.Format(@"{0}\{1}", path, file)) {
            // Если файл не найден - создаю
          //File.Create(string.Format(@"{0}\{1}", path, file));
            using ( File.Create(string.Format(@"{0}\{1}", path, file))) {};
        }
        // Если файл найден или создан - добавляю в файл текст
    File.WriteAllText(string.Format(@"{0}\{1}", path, file), "текст", Encoding.UTF8);
}
зачем вообще проверять существование и создавать файл? убери это
 
  • Спасибо
Реакции: LaGir

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 760
Благодарностей
2 398
Баллы
113
зачем вообще проверять существование и создавать файл? убери это
Потому что не всегда может быть операция записать в файл, а может быть например сразу по пути перевести в base64 - и тогда гарантировано будет ошибка что мол нет файла.
Хотя, я могу ошибаться, просто проще перестраховаться наперёд, да и логически вродебы правильно - если файла нет то что с ним собственно можно тогда делать?

Интересно) Что-то я даже не задумывался о таком "финте ушами". Расскажи потом как в многопотоке будет, если 1 и тот же файл кучей потоков обрабатывать таким способом (особенно интересует File.WriteAllText)
Наверно в многопотоке придется все-таки этот объект синхронизации использовать.
Но, пока этот момент не проверял.
Я чисто поверил на слово автору статьи, и просто сразу по-умолчанию использовал данную фишку.
А потом оказалось что выдает ошибку и решил разобраться почему этот lock не спасает.
Вот только впринципе логично - если должен спасать от многопотока, то явно не должен от ошибок в логике кода и не понимания, как вообще правильно работать с файлами в C#.
 

LaGir

Client
Регистрация
01.10.2015
Сообщения
211
Благодарностей
852
Баллы
93
Вопрос, что я делаю не так?
Добавлю, что мистики никакой нет, просто метод Create возвращает объект FileStream, для возможности дальнейшей работы с файлом.
FileStream1.png

Поэтому можно просто сразу закрыть его методом Close. Оборачивание в юзинг, впрочем, делает практически то же самое.
C#:
File.Create(path).Close();

Соответственно, лок тут вообще не при чём:
А потом оказалось что выдает ошибку и решил разобраться почему этот lock не спасает.
Вот только впринципе логично - если должен спасать от многопотока, то явно не должен от ошибок в логике кода и не понимания, как вообще правильно работать с файлами в C#.
 
  • Спасибо
Реакции: Metrix и BAZAg

uf0log

Client
Регистрация
29.05.2016
Сообщения
78
Благодарностей
19
Баллы
8
Необходимо создать свои собственные объекты синхронизации в Общем коде. По умолчанию там даже один уже есть:

Пожалуйста, объясните кто-нибудь на пальцах, как сделать это в Code Creator?
 

LaGir

Client
Регистрация
01.10.2015
Сообщения
211
Благодарностей
852
Баллы
93
Пожалуйста, объясните кто-нибудь на пальцах, как сделать это в Code Creator?
Вставить такие строчки объвления в любой подходящий класс, точно так же, как в Общем коде ProjectMaker.

Например, создаём файл для класса с объектами синхронизации:

2018-05-16_12-53-53.png


Даём подходящее название классу, заполняем его:

2018-05-16_12-59-48.png


После этого можно использовать локи с этими объектами в любых методах проекта:
C#:
lock (Lock.ProxyList)
{
    //... Тут действия со списком прокси, которые необходимо заблокировать
}
 
  • Спасибо
Реакции: uf0log

uf0log

Client
Регистрация
29.05.2016
Сообщения
78
Благодарностей
19
Баллы
8
Спасибо!
 

arhip1985

Client
Регистрация
31.10.2011
Сообщения
2 955
Благодарностей
781
Баллы
113
для лока файлов которые используют разные шаблоны - это годится или это не тот велосипед?
 

LaGir

Client
Регистрация
01.10.2015
Сообщения
211
Благодарностей
852
Баллы
93
для лока файлов которые используют разные шаблоны - это годится или это не тот велосипед?
Можно использовать стандартные локи, или вынести свои в dll, подключив её к этим шаблонам (т.е. чтобы локи были как внешний общий ресурс).
 
  • Спасибо
Реакции: arhip1985

backoff

Client
Регистрация
20.04.2015
Сообщения
5 925
Благодарностей
6 389
Баллы
113

linkod

Пользователь
Регистрация
11.10.2018
Сообщения
118
Благодарностей
1
Баллы
16
Можно использовать стандартные локи, или вынести свои в dll, подключив её к этим шаблонам (т.е. чтобы локи были как внешний общий ресурс).
Если вас не затруднит, то есть пример либы?
и еще момент, а если в общий код разных шахов добавить один и тот же код Лока?
 

one

Client
Регистрация
22.09.2015
Сообщения
6 793
Благодарностей
1 264
Баллы
113

LaGir

Client
Регистрация
01.10.2015
Сообщения
211
Благодарностей
852
Баллы
93
Если вас не затруднит, то есть пример либы?
На форуме по-моему несколько тем было по созданию либ в Visual Studio (вот например +- статья по теме). В данном случае нужно просто перенести локи из общего кода в либу, либу собрать и подключить к шаблонам - и можно пользоваться локами из либы.
и еще момент, а если в общий код разных шахов добавить один и тот же код Лока?
Насколько помню, для разных шаблонов это будут разные локи (так как и блок общего кода у каждого будет свой). В копиях одного и того же шаблона локи, соответственно, будут так работать (блок общего кода будет один на все копии шаба).
 

ZSharp

Client
Регистрация
29.09.2013
Сообщения
387
Благодарностей
121
Баллы
43
Понадобилось мне сделать, чтобы когда какой-то шаблон работает с файлом, чтобы все остальные не трогали.

Начал делать лок
lock (SyncObjects.ListSyncer)

а там пишут, что он устарел и нужно использовать новый лок
lock (FileSyncObjects.ListSyncer)

Вопрос.
Новый FileSyncObjects.ListSyncer тоже блокирует все шаблоны?
Если один использует турникет, все остальные заблокированы, даже на соседних станциях метро? )))

p.s. Про метро, отличнейший пример. :ay:
 

Mikhail B.

Moderator
Регистрация
23.12.2014
Сообщения
14 320
Благодарностей
5 424
Баллы
113
Начал делать лок
lock (SyncObjects.ListSyncer)

а там пишут, что он устарел и нужно использовать новый лок
lock (FileSyncObjects.ListSyncer)
Не знаю, кто такое пишет. Но вот этот лок, отлично работает со списками.
C#:
lock(SyncObjects.ListSyncer)
 

ZSharp

Client
Регистрация
29.09.2013
Сообщения
387
Благодарностей
121
Баллы
43
Не знаю, кто такое пишет.
Команда зеннолаба.
Так и пишут в библиотеке, что SyncObjects.ListSyncer является устаревшим, используйте FileSyncObjects.ListSyncer.


Код:
public class SyncObjects
{
    [Obsolete("Use FileSyncObjects.ListSyncer instead.")]
    public static readonly object ListSyncer;
    
    [Obsolete("Use FileSyncObjects.TableSyncer instead.")]
    public static readonly object TableSyncer;
    
    public static readonly object InputSyncer;

    public SyncObjects();
}
Может админы или модераторы прокомментируют?
 
  • Спасибо
Реакции: Mikhail B.

Mikhail B.

Moderator
Регистрация
23.12.2014
Сообщения
14 320
Благодарностей
5 424
Баллы
113

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)