Проблема с потоками

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by xmadstyle, 11 Sep 2010.

  1. xmadstyle

    xmadstyle Member

    Joined:
    29 Aug 2008
    Messages:
    91
    Likes Received:
    53
    Reputations:
    24
    Сабж столкнулся с проблемкой и без помощи тут не обойтись.
    Пишу брут, ЯП delphi.
    Вообщем приведу сразу код:
    Это процедура нажатия кнопки старт в основном потоке программы:
    Code:
    procedure TMainForm.bStartClick(Sender: TObject);
    var xid: longword;
    begin
      Acc:=TStringList.Create;  // для списка акков
      Pass:=TStringList.Create;  // для списка пассов
      // Дальше цикл перебора для каждого Acc - все Pass
      for i:=Acc.Count-1 downto 0 do  begin // i - глобальная integer
         for j:=0 to Pass.count-1 do begin  // j - глобальная integer
           // tid:array [0..999] of integer; глобальный массив, счетчик потоков
           tid[j]:=beginthread(nil,0,Addr(ThreadFunc),nil,0,Xid); //запускаем потоки
         end;
         // тут проверка на успешность выполнения всех потоков
      end;
      // тут вывожу результаты
    end;
    
    А это процедура нового потока:
    Code:
    procedure ThreadFunc;
    var  i_loсal, j_loсal: integer; // локальные i и j
           results: WideString;  // для результата пост запроса
           Post: TStringList;  // для пост запроса
           x_http: TIdHTTP;
           err: boolean; // для проверки успешности пост запроса  
    begin
      try
      // сохраняем глобальные переменные в локальные, чтобы потоки не конфликтовали
      i_lokal:=i; 
      j_lokal:=j;
      Post:=TStringList.Create;
    [COLOR=Green]  // ВОТ ЗДЕСЬ ПРОБЛЕМКА!!! 
      MainForm.lcurrent.Caption:='Acc: '+Acc[i_lokal]+'  Pass: '+Pass[j_lokal]; // вот этот label появляется в верхнем левом углу экрана[/COLOR]
      x_http:=TIdHTTP.Create(nil); // тут создаю динамически IdHTTP
      x_http.AllowCookies:=true;
      //Дальше определяю пост запрос 
      try
      results:=x_http.Post('xxx',Post); // сам пост запрос
      except err:=true; end; 
      Post.Clear;
      if(Length(results)>300) then begin // тут валид не валид условие
         // парсю нужные мне данные
         good:=good+1; // глобальная переменная для валид
    [COLOR=Green]     // ВОТ ЗДЕСЬ ПРОБЛЕМКА!!!
         MainForm.lGood.Caption:='Good: '+IntTostr(good);// тоже самое[/COLOR]
      end else begin
         bad:=bad+1;  // глобальная переменная для не валид
    [COLOR=Green]     // И ВОТ ЗДЕСЬ ПРОБЛЕМКА!!!
         MainForm.lBad.Caption:='Bad: '+IntTostr(bad); // и здесь тоже появляется этот label в верхнем левом углу экрана.[/COLOR]
      end;
      Post.Free; // Освобождаю Post;
      endthread(0); // закрываю поток
    end;
    
    Вообщем в коде написал коментарии, вот эти лэйблы ложатся друг на друга в верхнем левом углу экрана, причем форма моя находится по центру)) Такое конечно бывает не всегда, где-то 1 раз на 100-200 пост запросов, Если я не заключаю код в потоке в try except, то вылетает ексцепшен " in module 'xxx' at xxxxxxxx "Canvas does not allow drawing".
    Сам код c try exception работает без проблем, но вот эти лэйблы ужасно раздражают.
    Может быть кто-нибудь с талкивался с такой проблемкой?
     
    #1 xmadstyle, 11 Sep 2010
    Last edited: 11 Sep 2010
  2. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Доступ к визуальным компонентам только из main thread. Запомни это раз и навсегда.
    Версия дельфи?
    Нахера beginthread?
    Да, почти каждый день сталкиваюсь с проблемой отсуствия у новичков базовых знаний
     
    #2 GhostOnline, 11 Sep 2010
    Last edited: 11 Sep 2010
    1 person likes this.
  3. xmadstyle

    xmadstyle Member

    Joined:
    29 Aug 2008
    Messages:
    91
    Likes Received:
    53
    Reputations:
    24
    Т.е. из потока мне никак не получится изменить визуальные компоненты формы?
    7
    А чем плохо?

    Спасибо за то, что уделил минутку времени, и ответил на мой вопрос, да вообще какие-либо знания о потоках у меня отсутствовали до не давнего времени, теперь пытаюсь наверстать упущенное.
     
  4. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Вот так напрямую - нет. Надо сделать так чтобы операции с компонентами на форме производились только в контексте главного потока. Если бы ты использовал TThread то можно было бы воспользоваться методами Synchronize и Queue для этого. Либо если версия дельфи была бы поновее то статическими методами класса TThread которые можно вызывать в любом месте программы не создавая объекта. А так, даже не знаю, возможно воспользоваться посылкой сообщений SendMesage/PostMessage.. Но TLabel не оконный компонент, сам сообщения обрабатывать не может. Как вариант определить метод в классе формы для обработки сообщения, а в потоке посылать сообщение с помощью SendMessage. Тогда все будет работать нормально.
    А тем, что смешивание методологий и парадигм. С одной стороны ты юзаешь готовые классы/компоненты а с другой напрямую APi-функции. Вот как результат получаем костыли описанные выше.

    А вообще, интересно, у тебя что, TLabel новый создается при этом, или старый перемещается?
     
    #4 GhostOnline, 11 Sep 2010
    Last edited: 11 Sep 2010
  5. Redeemer

    Redeemer Member

    Joined:
    3 Jul 2010
    Messages:
    203
    Likes Received:
    24
    Reputations:
    1
    Code:
    procedure TMainForm.bStartClick(Sender: TObject);
    var xid: longword;
    begin
      Acc:=TStringList.Create;  // для списка акков
      Pass:=TStringList.Create;  // для списка пассов
      // Дальше цикл перебора для каждого Acc - все Pass
      for i:=Acc.Count-1 downto 0 do  begin // i - глобальная integer
         for j:=0 to Pass.count-1 do begin  // j - глобальная integer
           // tid:array [0..999] of integer; глобальный массив, счетчик потоков
           tid[j]:=beginthread(nil,0,Addr(ThreadFunc),nil,0,Xid); //запускаем потоки
         end;
         // тут проверка на успешность выполнения всех потоков
      end;
      // тут вывожу результаты
    end;
    Так никто не делает. Что если у тебя будет 100 паролей и 100 акков? Правильней создать очередь и фиксированное число потоков для ее обслуживания.
     
  6. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    ++
    а еще лучше не фиксированное число потоков а пул потоков на основе порта завершения ввода вывода
    и глобальную очередь доступ к которой синхронизировать секциями
     
  7. xmadstyle

    xmadstyle Member

    Joined:
    29 Aug 2008
    Messages:
    91
    Likes Received:
    53
    Reputations:
    24
    Спс за ценные советы, учту. Вообще я перенес в основной поток все визуальные преобразования и теперь ничего не появляется и все работает без эксцепшен. Ещё раз Спасибо за базу.
    Вообще я пробовал использовать Indy компонент для работы с потоками TIdThreadComponent, но ничего хорошего не вышло.
    Да и на форумах часто видел люди писали, что глючит Indy.
    Поэтому решил на Апи реализовать, да и не сложно в освоении впринципе.

    Новый создавался, потому как на самой форме изменения были видны без проблем одновременно с появлением копий этих изменений в верхнем углу экрана.

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

    Спасибо всем, кто помог разобраться так сказать в азах, даже стыдно немножко) Проблема решена. Тему можно закрывать.
     
  8. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    QueueUserWorkItem выполняет callback функции в пуле при необходимости увеличивает количество потоков при необходимости уменьшает тоесть весь код обслуживающий пул уже написан можно просто ей воспользоваться останется только написать свой callback и внутри него синхронизировать доступ к очереди хотя да здесь все таки лучше фиксированное число потоков если бы была неизвестна частота запросов и нагрузка то пул был бы лучшим решением
     
    #8 greki_hoy, 11 Sep 2010
    Last edited: 11 Sep 2010