взаимодействие потоков с формой. как грамотно реализовать?

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by good_man, 1 Oct 2010.

  1. good_man

    good_man New Member

    Joined:
    24 May 2010
    Messages:
    112
    Likes Received:
    3
    Reputations:
    -2
    Доброго времени суток тру кодеры! объясните чайнику как грамотно организовать взаимодействие/работу билдеровских потоков (TThread) с визуальными элементами/компонентами формы. пробывал юзать Synchronise. с этим методом прога дохнет быстрей чем при прямом обращении к компоненту. тестил вчера на спамере стен.

    думал как выводить кол-во отправленых сообщений... пришла в голову тупая мысль: кинуть на форму таймер и выводить значение переменной в лейбл...

    но как тогда вобще грамотно выводить сообщения скажем в MemoLog? (в головву только приходит опять же тупая мысль: сохранять в файл и оттуда читать) в общем я в тупике. выручайте. заранее благодарю. надеюсь более менее понятно изложил суть проблемы.
     
  2. brutos

    brutos Member

    Joined:
    25 Nov 2009
    Messages:
    123
    Likes Received:
    27
    Reputations:
    8
    Лично у меня это реализовано с помощью трех объектов: таймер, лейбл и переменная. В синхронизации поток передает результат в эту переменную, а таймер через заданный промежуток времени выводит в лейбл значение этой переменной. Вот и все.

    Пример:
    Code:
    unit MyThread;
    ...
    procedure TMyThread.Sync;
    begin
      Inc(Param);
    end;
    ...
    
    
    unit Main;
    ...
    //Глобальные переменные
    var
      Form1: TForm1;
      Param:integer;
    ...
    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      Label1.Caption:='Готово: '+IntToStr(Param);
    end;
    ...
    Для MemoLog'а также можно использовать переменную. Типа TStringList, например.
     
    #2 brutos, 1 Oct 2010
    Last edited: 1 Oct 2010
  3. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    brutos твой подход ошибочен, т.к. сама модификация Param происходит в потоке. в случае с целыми достаточно InterLockedIncrement а вот с TStringList так делов наворотишь, потом будешь плеваться откуда баги на ровном якобы месте.
    good_man способов с визуальными элементами только два - Syncronize и Queue.
    Если у тебя что-то не так - значит не так сделано.

    Аа, вру, еще есть с отправкой сообщений венды, но это для тебя сложновато и объяснять долго.
     
    #3 GhostOnline, 1 Oct 2010
    Last edited: 1 Oct 2010
  4. good_man

    good_man New Member

    Joined:
    24 May 2010
    Messages:
    112
    Likes Received:
    3
    Reputations:
    -2
    ах да, еще чуть не забыл, очень меня мучает такой вопрос:

    многопоточность. запутался. создаю потоки:

    for(int i=0; i<thr_count; i++)
    {
    Wall_Sender*thr[100];
    thr=new Wall_Sender(true);
    thr->Resume();
    }

    то есть все они создаются почти моментально. нужно взять из мемо аки:

    String acc= Form1->MemoAccs->Lines->Strings[accs]; //accs-глобальная int
    String login=acc.SubString(1,acc.Pos(":")-1);
    String pass=acc.Delete(1,acc.Pos(":"));


    Form1->MemoLog->Lines->Add(pass+":"+login);

    как сделать? вот это для меня настоящий тупик. то есть если воткнуть accs++ даже после String acc= Form1->MemoAccs->Lines->Strings[accs]; , выбрать много потоков то они будут брать один и тот же ак. А теперь еще вопрос: можно ли так вобще делать? читать и обращаться напрямую к мемо из потока ?

    upd:
    GhostOnline

    вчера всю ночь сидел изучал работу проги. почти после каждой операции логировал. код у меня минимален и в нем я как бы разбираюсь. прога висла все время перед кодом где идет обращение к визуальному компоненту.
     
    #4 good_man, 1 Oct 2010
    Last edited: 1 Oct 2010
  5. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    нет, нет, и еще раз нет
    Почему бы не завести поле в классе потока и не передавать акк ему в конструктор?
    Видимо плохо понимаешь. Длительные операции внутри Synchronize обычно к такому приводят.
     
    #5 GhostOnline, 1 Oct 2010
    Last edited: 1 Oct 2010
  6. good_man

    good_man New Member

    Joined:
    24 May 2010
    Messages:
    112
    Likes Received:
    3
    Reputations:
    -2
    можно поподробнее? что за поле? и как ему передавать?) я не совсем прогер. просто любитель. кодю нетак давно.
     
  7. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Поподробнее то можно, но целесообразно ли.
    Объясню это - появятся другие вопросы, и так далее, рекурсия
    Раз уж ты любитель, то время у тебя есть и торопиться некуда - почитай про классы.
     
  8. good_man

    good_man New Member

    Joined:
    24 May 2010
    Messages:
    112
    Likes Received:
    3
    Reputations:
    -2
    GhostOnline ну хотя бы вкратце. у меня в личке столько литературы ппц (скинул один добрый человек) просто читать долго+задолбаешься искать именно по этой теме. а у меня спамер полудохлый так и просит доделать его. мне аж кошмары снятся. как доделаю буду читать книги :)
     
  9. HakaR

    HakaR Active Member

    Joined:
    23 Jul 2009
    Messages:
    301
    Likes Received:
    200
    Reputations:
    3
    Критические секции.

    Как то так (Delphi)
    PHP:
    CriticalS.Enter;
      
    Inc(ThreadCount);
      
    t_num := ThreadCount;
      
    MainForm.LogText.Lines.Add('Поток #'+IntToStr(t_num)+' создан.');
     
    CriticalS.Leave;
     
  10. good_man

    good_man New Member

    Joined:
    24 May 2010
    Messages:
    112
    Likes Received:
    3
    Reputations:
    -2
    ребят а можно делать так:

    void __fastcall WallSend::ImageLoad()
    {
    Form1->Image1->Picture->LoadFromFile(wall_cap_sid+".jpg");
    }
    void __fastcall WallSend::UpdateMemoLog()
    {
    Form1->MemoLog->Lines->Add("отправлено на стену "+friends->Strings[fr_id]);
    }
    void __fastcall WallSend::UpdateLabel3()
    {
    Form1->Label3->Caption=mess_count;
    }

    ? и как быть с вопросом #4?
     
  11. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Фэйл. Для кого авторы постоянно подчеркивают что с формой может работать только main thread?
    Критические секции надо использовать при общем доступе к данным, а не визуальным элементам.
    А Synchronize как раз гарантирует что метод будет выполнен в контексте главного потока.
    С++ вообще не знаю, но попытаюсь изобразить
    В классе потока добавляешь поле, что-то навроде:
    PHP:
    class Wall_Sender TThread{
      .........................
      private 
    String Account;
      ........................
    }
    Переопределяешь конструктор класса потока, мм..мб так как-то:
    PHP:
     Wall_Sender(String Acc)
     {
       ...........
       
    Account Acc;
       ...........
      
    Resume;
      }
    То бишь Account это строка вида login;pass
    А создаешь уже так:
    PHP:
    thr[i]=new Wall_Sender(Form1->Memo1->Lines[i]);
     
    #11 GhostOnline, 1 Oct 2010
    Last edited: 1 Oct 2010