Эксперимент по выявлению пересечений буфера обмена при работе в многопотоке

eee

Client
Регистрация
04.06.2018
Сообщения
134
Благодарностей
31
Баллы
28
у меня код Bazag в 10 потоков работает без ошибок (остальные варианты работали некорректно). тс потестит, отпишется
Вы тестировали на FF52x64 ? В этом браузере код отрабатывает на 100%, но в Chrome потоки пересекаются
 

volody00

Client
Регистрация
06.09.2016
Сообщения
794
Благодарностей
814
Баллы
93

eee

Client
Регистрация
04.06.2018
Сообщения
134
Благодарностей
31
Баллы
28

volody00

Client
Регистрация
06.09.2016
Сообщения
794
Благодарностей
814
Баллы
93
странно у меня в Хроме некорректно отрабатывает
проверил ещё раз. да, бывает проскакивает оказывается. да забей уже на эту хренотень. опиши задачу, её почти наверняка можно и по другому решить. ну или заплати Bazag $10 (или сколько он там попросит), чтобы он до ума довел (может я лишнее обрезал, просто там выполнялось очень медленно)
 
  • Спасибо
Реакции: eee

volody00

Client
Регистрация
06.09.2016
Сообщения
794
Благодарностей
814
Баллы
93
попробуй с паузой ещё (вроде норм, но лень ждать пока всё отработает, может и косячит всё равно):

C#:
string line = project.Variables["article_title"].Value;
string md5 = line.GetMD5Hash();
string new_md5_1 = string.Empty;
string old_clip = string.Empty;
string new_md5_2 = string.Empty;
int item = 0;
lock (SyncObjects.InputSyncer) {
    while(md5 != new_md5_1) {
        item++; // Счётчик попыток добавления в буфер
           try {
            System.Windows.Forms.Clipboard.Clear();
            System.Windows.Forms.Clipboard.SetText(line);
            new_md5_1 = System.Windows.Forms.Clipboard.GetText().GetMD5Hash();
        }
        catch {
            project.SendWarningToLog("Ошибка добавления данных в буфер",true);
            Thread.Sleep(100);
        }
    }
    instance.ActiveTab.KeyEvent("v", "press", "ctrl");

    new_md5_2 = System.Windows.Forms.Clipboard.GetText().GetMD5Hash();
    
    System.Windows.Forms.Clipboard.Clear();
    Thread.Sleep(1000);
}
 

Вложения

  • 19,2 КБ Просмотры: 63
  • Спасибо
Реакции: eee

eee

Client
Регистрация
04.06.2018
Сообщения
134
Благодарностей
31
Баллы
28
попробуй с паузой ещё (вроде норм, но лень ждать пока всё отработает, может и косячит всё равно):

C#:
string line = project.Variables["article_title"].Value;
string md5 = line.GetMD5Hash();
string new_md5_1 = string.Empty;
string old_clip = string.Empty;
string new_md5_2 = string.Empty;
int item = 0;
lock (SyncObjects.InputSyncer) {
    while(md5 != new_md5_1) {
        item++; // Счётчик попыток добавления в буфер
           try {
            System.Windows.Forms.Clipboard.Clear();
            System.Windows.Forms.Clipboard.SetText(line);
            new_md5_1 = System.Windows.Forms.Clipboard.GetText().GetMD5Hash();
        }
        catch {
            project.SendWarningToLog("Ошибка добавления данных в буфер",true);
            Thread.Sleep(100);
        }
    }
    instance.ActiveTab.KeyEvent("v", "press", "ctrl");

    new_md5_2 = System.Windows.Forms.Clipboard.GetText().GetMD5Hash();
   
    System.Windows.Forms.Clipboard.Clear();
    Thread.Sleep(1000);
}
этот отрабатывает получше в плане пересечения потоков, но не каждый раз вставляет значения, много пропусков.
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 766
Благодарностей
2 408
Баллы
113
Дело в том, что у меня проблема не обнаруживается - у меня всё работает корректно.

То, что проект долго выполняется - это логично - если мы делаем лок - то момент работы с буфером выполняется в 1 поток - остальные потоки должны ждать своей очереди, а далее instance.instance.ActiveTab.KeyEvent("v", "press", "ctrl"); может выполняться сколько угодно времени (либо количество времени, которое выставлено в настройках выполнения проекта, например вот здесь если поставить какое-то значение, то возможно будет прерывать работу и в итоге будут теряться данные.
79040


Но, это ещё не всё... Может оказаться случайно так, что памяти между процессами недостаточно - возможно это значение нужно увеличить. Или например приоритетные потоки не дают вовремя взять инстанс чтобы выполнить в нём команду вставки.
79041


А ещё может быть, что в настройках установлено маленькое время выполнения команды в инстансе...
Или, в момент выполнения количество памяти браузера маловато.
Или банально теряется фокус инстанса, из-за чего при вставке Ctrl+V не отрабатывает вставка в нужное поле.
79042


Или возможно ещё необходимо состояние занятости инстанса подправить, так как вдруг в момент вставки данных оказывается что инстанс занят загрузкой в фреймах или ajax что-то принимает/отправляет и инстанс не может принимать данные...
C#:
instance.IgnoreAjaxRequests = false;
instance.IgnoreAdditionalRequests = false;
instance.IgnoreFrameRequests = false;
instance.IgnoreFlashRequests = false;
Кроме этого, вводятся данные или нет и теряются где-то или нет может быть связано с настройками эмуляции ввода (как и скорость отработки команды вставки).
79043


То что код работает нормально с буфером - это мне понятно, но вот что именно и как происходит при выполнении команды instance.ActiveTab.KeyEvent("v", "press", "ctrl"); - мне лично не понятно :(

Я запустил код с Chrome в несколько потоков, покрутил - и в результате у меня проблемы нет - всё работает корректно (если самому не трогать буфер).
79044

79045


Код который использовал (для скриншота выше):

C#:
instance.SetProxy("http://127.0.0.1:8888"); // устанавливаю прокси фиддлера
instance.ActiveTab.Navigate("https://ya.ru");// Перехожу в яндекс
instance.ActiveTab.FindElementById("text").RiseEvent("click", instance.EmulationLevel);// кликаю по форме (чтобы поле было в фокусе

int max = 100; // Определяю сколько раз буду нажимать ctrl+v
string line = Enumerable.Range(0,10).OrderBy(x=> Guid.NewGuid()).First().ToString(); // Генерирую случайное число
string md5 = line.GetMD5Hash(); // Вычисляю хеш с данного числа
string new_md5_1 = string.Empty;
int item = 0;
lock (SyncObjects.InputSyncer) { // Блокирую буфер
    string old_text = System.Windows.Forms.Clipboard.GetText(); // Извлекаю содержимое буфера, чтобы вернуть обратно
    while(md5 != new_md5_1) { // Если содержимое буфера отличается от желаемого - пытаюсь добавить туда содержимое
        item++; // Счётчик попыток добавления в буфер
        try {
            System.Windows.Forms.Clipboard.Clear(); // Очистка буфера
            System.Windows.Forms.Clipboard.SetText(line); // Установка текста
            new_md5_1 = System.Windows.Forms.Clipboard.GetText().GetMD5Hash(); // Извлечение хеша, для проверки и выхода с цикла
        }
        catch {
            System.Windows.Forms.Clipboard.SetText(old_text); // Если произошла попытка добавления в буфер - возвращаю назад старый текст, выхожу по ошибке
            throw new Exception("Ошибка добавления данных в буфер");
        }
    }
    string attribute = string.Empty; // Содержимое поля ввода
    int count = 0; // Количество введённых данных в поле
    for(int i=0; i<2*max ;i++) { // Цикл, который позволит нажать необходимое количество раз Ctrl + V  
        // i<2*max - специально поставил 2*max, если вдруг браузер не отреагировал на событие Ctrl+V - позволит сделать ещё одну попытку
        attribute = string.Empty;
        attribute = instance.ActiveTab.GetDocumentByAddress("0").FindElementByTag("form", 0).FindChildById("text").GetAttribute("value"); // узнаю сколько раз уже нажимал Ctrl + V
        count = attribute.Count(x => x == line[0]); // Считаю количество совпадений
        if(max == count) break; // Если необходимое количество данных введено - выхожу с цикла
        else instance.ActiveTab.KeyEvent("v", "press", "ctrl"); // Иначе ещё раз нажимаю Ctrl + V  
    }
    
    System.Windows.Forms.Clipboard.Clear(); // очистил буфер
    System.Windows.Forms.Clipboard.SetText(old_text); // Вернул туда что было
    string mess = string.Format(@"{0} {1} {2}",line, count, attribute);
    
    if(max == count) project.SendInfoToLog(mess,true); // Синее сообщение если данных достаточно в поле
    else project.SendWarningToLog(mess,true); // Желтое, если не достаточно    
}
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 691
Баллы
113
Это все очень интересно и познавательно, но все это про зенку. А буфер обмена не относится к зенке и как показали тесты на 4-х разных машинах, в 50% случаев ведет себя по разному.
Поэтому я и написал ранее, что этот механизм не гарантирует установку и извлечение нужных данных для конкретного потока. Например все эти проверки у меня ни разу не дали сигнала о том что в буфере находится не тот текст, что установил текущий поток. А в поле ввода проскакивает контрольный текст, который я специально оставил в буфере перед запуском шаблонов.
Ну и даже если добится, более менее стабильной работы, через какие то настройки зенки, даже если контролить вставленный текст с текстом что появился в поле ввода (а иногда это не возможно, так как некоторые поля тут же меняют верстку текста) , то это не будет универсальным решением и под каждый сайт, под каждую машину придется делать полную отладку и проверку работоспособности этой вставки в поле.
Поэтому не надо делать костыли к методу, который для этого не предназначен.
Все можно сделать встроенными методами зенки. Автора просили озвучить поставленную задачу, что бы решить его вопрос, но он уперто ковыряет мертвую тему. Значит так ему надо решить этот вопрос.
Уж сколько раз приходилось вставлять текст в разные синнонимайзеры, всякие разные переводчики (по 400-5000 символов), и нигде не пришлось опускаться до уровня буфера обмена.
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 766
Благодарностей
2 408
Баллы
113
Это все очень интересно и познавательно, но все это про зенку. А буфер обмена не относится к зенке и как показали тесты на 4-х разных машинах, в 50% случаев ведет себя по разному.
Поэтому я и написал ранее, что этот механизм не гарантирует установку и извлечение нужных данных для конкретного потока. Например все эти проверки у меня ни разу не дали сигнала о том что в буфере находится не тот текст, что установил текущий поток. А в поле ввода проскакивает контрольный текст, который я специально оставил в буфере перед запуском шаблонов.
Ну и даже если добится, более менее стабильной работы, через какие то настройки зенки, даже если контролить вставленный текст с текстом что появился в поле ввода (а иногда это не возможно, так как некоторые поля тут же меняют верстку текста) , то это не будет универсальным решением и под каждый сайт, под каждую машину придется делать полную отладку и проверку работоспособности этой вставки в поле.
Поэтому не надо делать костыли к методу, который для этого не предназначен.
Все можно сделать встроенными методами зенки. Автора просили озвучить поставленную задачу, что бы решить его вопрос, но он уперто ковыряет мертвую тему. Значит так ему надо решить этот вопрос.
Уж сколько раз приходилось вставлять текст в разные синнонимайзеры, всякие разные переводчики (по 400-5000 символов), и нигде не пришлось опускаться до уровня буфера обмена.
На сколько я понимаю, что проблема создателя топика не в том, что он не сможет решить задачу без буфера обмена.
По-моему мнению, все мы хотели бы понять почему буфер обмена в многопотоке всё же ведёт себя у всех по разному, не смотря на локи.
И другой вытекающий вопрос - влияет ли лок, как мы ожидаем, на instance.ActiveTab.KeyEvent("v", "press", "ctrl");.
Потому, что если буфер обмена как-то мешает данные - то видимо всё таки лок не работает так как мы ожидаем - а это уже тогда ошибка Зенно.

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

Ведь в таком случае пишем
C#:
lock(SyncObjects.InputSyncer){
// сюда любой объект с которым собрались работать - и получили фиг-знает-чего вместо однопотока
}
... а это уже серьезная предъява...
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 691
Баллы
113
На сколько я понимаю, что проблема создателя топика не в том, что он не сможет решить задачу без буфера обмена.
По-моему мнению, все мы хотели бы понять почему буфер обмена в многопотоке всё же ведёт себя у всех по разному, не смотря на локи.
И другой вытекающий вопрос - влияет ли лок, как мы ожидаем, на instance.ActiveTab.KeyEvent("v", "press", "ctrl");.
Потому, что если буфер обмена как-то мешает данные - то видимо всё таки лок не работает так как мы ожидаем - а это уже тогда ошибка Зенно.

Естественно, что решить проблему можно разными способами, и чтобы не использовать буфер обмена достаточно просто найти нужный запрос и подставлять данные уже в него, или вообще переписать шаблон на запросы или...
Но, вопрос всё таки остается о буфере обмена - почему данные между потоками смешиваются?
Почему у меня результат отличается от других пользователей, хотя код запускается идентичный?
Если рассуждать чисто про буфер обмена, то как можно контролировать механизм винды ? Ответ , никак. Вот как работает так и работает. Захотела винда заглючить в данный момент, она и заглючила.
Лок работает прекрасно. Другое дело что буфер может отработать с задержкой. если мы в локе отправляем данные в БД, то мы полагаемся на ее систему транзакций, тоесть достаточно в локе отправить данные и они не перепутаются там. В зенке , с списках и в таблицах, тоже есть что то подобие транзакций, раз лок помогает брать строки последовательно.
А в винде многое построено на посылке сообщений, и есть ли там механизм транзакций мы не знаем. Судя по тестам, буфер не всегда реагирует сразу и мгновенно, поэтому увеличение пауз внутри лока помогает уйти от пересечений данных между потоками (тупо буфер успевает отработать данные из других потоков) , но причину появления старых данных по ctrl + v я понять не могу, так как делал двойную проверку, до вставки в буфер и сразу после вставки в буфер. и у меня ни разу не возникло события, когда данные не бьются. Однако визуально я вижу что иногда вбивается не то что надо.
Поэтому скорее всего тут проблема не в локе, а в механизме ctrl+v и самом буфере. Ну и раз наблюдаются несоответсвия между считываемыми данными в коде и данными по ctrl+v , то надо признать что буфер обмена не контролируем, а соответственно, практически не пригоден для многопотока.
 

volody00

Client
Регистрация
06.09.2016
Сообщения
794
Благодарностей
814
Баллы
93
Дело в том, что у меня проблема не обнаруживается - у меня всё работает корректно.
В том коде, что ты скинул последним, работа идет в последовательно, поэтому у тебя не воспроизводится. ТС же блокировал только тот участок, где кладется в буфер и вставляется. Запусти прикрепленный шаблон в этом сообщении. За основу я взял твой код, можешь поискать косяк, если хочешь
 

Вложения

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 766
Благодарностей
2 408
Баллы
113
За основу я взял твой код, можешь поискать косяк, если хочешь
Я не могу отвечать за чужой код - когда Вы его писали, то явно руководствовались какими-то своими принципами, и возможно что-то увидели такое, чего не увидел я, раз решили кастрировать код который я собирал (посчитали его избыточным например).
Но, обратную связь дам конечно (обратно таки, это только мое мнение):
79051


Важно взять данные с буфера и вернуть на место.
Чтобы не добавлять паузы между локами - я решил не выходить с лока - из-за чего переписал код в один кубик.
Чтобы не искажать данные изменением фокуса окна - я переписал вывод на вывод в лог и убрал этот кубик.
Так как ТС делал скриншоты инстансов - менялся фокус - это могло также повлиять на результат (как и сам кубик ожидание действий пользователя).

Да, данный код, который на скриншоте отрабатывает с ошибками (мешается буфер).

Если рассуждать чисто про буфер обмена, то как можно контролировать механизм винды ? Ответ , никак. Вот как работает так и работает. Захотела винда заглючить в данный момент, она и заглючила.
При необходимости мы можем получать события от буфера обмена (что по идее было бы правильно написать, чтобы отладить весь процесс и понять что происходит - но, я пока с событиями совсем не дружу), и уже в случае когда собитие произошло, и в буфере в данный момент нужные данные - тогда выполнить какой-то обработчик, например Ctrl+V в указанное окно. Но, скажем так, я так не умею, и как Вы говорите - в данном случае это и не нужно.

в механизме ctrl+v
Именно, видимо этот механизм не успевает отправить содержимое буфера в нужное окно, или например два последовательных ввода за слишком краткий промежуток времени например игнорируется виндой или ещё чего...
 
  • Спасибо
Реакции: volody00

kagorec

Client
Регистрация
24.08.2013
Сообщения
923
Благодарностей
477
Баллы
63
Одно из решений от ChatGPT
C#:
string str = project.Variables["txt"].Value;
string[] split = str.Split(new string[] { @"\r\n" }, StringSplitOptions.RemoveEmptyEntries);

// Создаем новый объект буфера обмена для текущего потока
var threadClipboard = new System.Windows.Forms.DataObject();

// Сохраняем предыдущее состояние буфера
string previousText;
lock (SyncObjects.InputSyncer)
{
    previousText = System.Windows.Forms.Clipboard.GetText();
}

lock (threadClipboard)
{
    // Сохраняем нужный текст в буфер и вставляем его (программно делаем CTRL+V)
    for (int i = 0; i < split.Length; i++)
    {
        threadClipboard.SetText(split[i]);
        System.Windows.Forms.Clipboard.SetDataObject(threadClipboard, true);
        instance.ActiveTab.KeyEvent("v", "press", "ctrl");

        if (i < split.Length - 1)
            instance.SendText("{ENTER}", 1);
    }

    // Очищаем буфер обмена текущего потока
    System.Windows.Forms.Clipboard.Clear();
    System.Windows.Forms.Clipboard.SetDataObject(previousText, true);
}
 

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