Потоки и ВК (Execute потока)

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by Problems?, 18 Apr 2011.

  1. Problems?

    Problems? Member

    Joined:
    13 Jan 2011
    Messages:
    14
    Likes Received:
    9
    Reputations:
    5
    Ребят вот не могу разобраться с такой фишкой, переодически пишу спамеры для вк, но иногда бывают проблемы (спамер, не всем рассылает, когда я изпользую многопоточное приложение)

    Для органицации потоков и синхронизации с аккаунтами, написал вот такой обработчик

    где SL = список аккантов
    Counter = текущий индекс в списке SL
    ToSpamSL = кому слать (список)
    IndToSpam = индекс в списке кому рассылать

    Code:
    procedure TMyThread.Execute;
    var Str, Save_Str, Sender, Msg, Link: string;
        Info: TMyInfo;
        Client: TMP3Rnd;
        IsLogin: boolean;
        Login, pass: string;
        IsMention: boolean;
    begin
      InterlockedIncrement(threads_alive);
      try
      while (not Self.Terminated)  do begin
          // cs_enter
          CS_Thr.Enter;
           InterlockedIncrement(IndToSpam);
            if Counter >= SL.Count - 1 then Counter:=0
              else InterlockedIncrement(Counter); //Inc(Counter);
          CS_Thr.Leave;
          // cs_leave
          // парсим login, pass
          Str:=SL.Strings[Counter]; if Str='' then continue;
          data:=str; Save_Str:= data; // для отладки
          Login:=copy(Save_Str,0,pos(ChrSep,Save_Str)-1);
       pass:=copy(Save_Str,pos(ChrSep,Save_Str)+1,length(Save_Str)-pos(ChrSep,Save_Str));
          // ----
          Str:= ToSpamSL.Strings[IndToSpam]; if Str='' then continue;
          //Form1.LogMemo.Lines.Add('авторизация ... '+Login);
          Msg    := ''; //Rnd_StrWithList(RndMsgSL);
          data:=Login + ' '+ Str + ' '+ ' ' + Msg ;
          ID:=Str;
            // ..
          //CS_Thr.Enter;
            Client:= TMP3Rnd.Create;
            IsLogin := Client.Login(Login,Pass,'','');
            if IsLogin then begin
              inc(Valid);
              //Form1.LogMemo.Lines.Add('авторизация ... ok');
              Info := Client.GetMyInfo(Str); 
              ISMention:=false;
              if Form1.CheckBox4.Checked then
                  msg :=  Rnd_StrWithList(RndMsgSL)
                   else begin msg := Form1.Memo3.Text;
                              if Form1.CheckBox1.Checked then msg:=msg+#13#10#13#10+'['+Str+']'; // дописываем  to_id
                   end;
              IsMention:=Client.PostWall(Info.WallHash, '', info.ID, '', msg,'','','','');
              if IsMention then begin
                ISSend.Add(Str);
                inc(CntSend) // успешно
                end
                else begin
                      //NotSendingSL.Add(Str);
                      inc(NotSend);
                     end;
            end
              else inc(NotValid);
            Client.Free;
          // ....
          //CS_Thr.Leave;
          Synchronize(UpdateGUI);
          sleep( MyRandomRange(SleepTo, SleepDo) );
          //end; //if
      end;
      finally
      //Synchronize(UpdateGUIDec);
      InterlockedDecrement(threads_alive);
      end;
    end;
    
    Вроде бы все хорошо, но если я изпользую не 1 поток, а 5 к примеру, то спамер может разослать не всем (т.е. 50/50), в чем может быть причина? Организация потока и синхронизации со список аккаунтов и списком рассылки верная? подскажите..
    P.S: иcпользую Indy (Delphi 7)
     
  2. greki_hoy

    greki_hoy Member

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

    Problems? Member

    Joined:
    13 Jan 2011
    Messages:
    14
    Likes Received:
    9
    Reputations:
    5
    под работой с GUI вы подразуемеваете
    Code:
    Form1.CheckBox4.Checked, Form1.Memo3.Text 
    ?

    Но просто читать вроде бы атрибуты компонента можно.

    Работа с ГУИ конкретно со статистикой у меня четко разделено, вот синхронизация:
    Code:
    Synchronize(UpdateGUI);
    Для того чтобы не было, что один аккаунт с одного потока, юзается в другом, с таким же индексом.

    Т.е. без такой конструкции, было такое (не знаю с чем это связано)

    Поток 1 Аккаунт 1 Сообщение
    Поток 2 Аккаунт 1 Сообщение
    Поток 3 Аккаунт 1 Сообщение
    ...
    Поток 1 Аккаунт 2 Сообщение
    Поток 2 Аккаунт 2 Сообщение

    [Такое я наблюдал на этапе отладки]

    Изпользуя interlocked внутри critical section (или Inc, кстати особой разницы я не заметил) , каждый поток юзает свой аккаунт параметр Count, отражает индекс элемента в списке

    Поток 1 Аккаунт 1 Сообщение
    Поток 2 Аккаунт 2 Сообщение
    Поток 3 Аккаунт 3 Сообщение
     
  4. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    а где обработка исключений? если возникнет експшн внутри Execute то поток завершится
    как вариант - отлавливай событие OnTerminate у потока, в нем проверяй все ли отправлено, если нет то запускай новый поток (да, быдлокодерски, но в твоем случае пойдет, ибо в твой код трудно вникнуть)
     
  5. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    Code:
     // cs_enter
          CS_Thr.Enter;
           InterlockedIncrement(IndToSpam);
            if Counter >= SL.Count - 1 then Counter:=0
              else InterlockedIncrement(Counter); //Inc(Counter);
          CS_Thr.Leave;
          // cs_leave
          // парсим login, pass
          Str:=SL.Strings[Counter]; if Str='' then continue;
          data:=str; Save_Str:= data; // для отладки
          Login:=copy(Save_Str,0,pos(ChrSep,Save_Str)-1);
       pass:=copy(Save_Str,pos(ChrSep,Save_Str)+1,length(  Save_Str)-pos(ChrSep,Save_Str));
          // ----
          Str:= ToSpamSL.Strings[IndToSpam]; if Str='' then continue;
    
    вот строчки интересные а что если первый поток 1)
    сделает InterlockedIncrement(Counter); потом выйдет CS_Thr.Leave;
    и его вытеснит планировщик потом войдет второй поток 2)
    сделает InterlockedIncrement(Counter); выйдет CS_Thr.Leave;
    они оба окажутся в этой точке
    Code:
     
    --->>>
    Str:=SL.Strings[Counter]; if Str='' then continue;
          data:=str; Save_Str:= data; // для отладки
          Login:=copy(Save_Str,0,pos(ChrSep,Save_Str)-1);
       pass:=copy(Save_Str,pos(ChrSep,Save_Str)+1,length(  Save_Str)-pos(ChrSep,Save_Str));
          // ----
          Str:= ToSpamSL.Strings[IndToSpam]; if Str='' then continue;
    
    и у них у обоих одитнаковые индексы или так задумано ?
    судя по этому коду interlocked не нужен внутри critical section
    можно проосто inc(Counter)
    но вытаскивать то на что указывают индексы надо в критической секции
    всю работу не относящуюся к синхронизации убрать в отдельную функции за этой шелухой теряется сама синхронизация
     
  6. Problems?

    Problems? Member

    Joined:
    13 Jan 2011
    Messages:
    14
    Likes Received:
    9
    Reputations:
    5
    Данная проблема наблюдалась и при inc(Counter), думал потоко-безопасное увелечение
    InterlockedIncrement(Counter), решит проблему, но этого не произошло.
    Хм, т.е. строки на акки и сообщения, в крит секции? Хорошо попробую.

    Поясните подробней, желательно с примером как это детально реализовать?
     
  7. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    ну вот как нить так чтоб выглядел главный цикл
    ничего не относящегося к синхронизации и условию завершения
    Code:
    ... thread ...
    {
    	while (!terminated)
    	{
    		lock();
    		stuff_t local_stuff = unpack_next_stuff();
    		unlock();
    		
    		do_something(local_stuff); 
    	}
    }
    
     
  8. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    иль на сишке можно даже так
    Code:
    ... thread ...
    {
    	switch (need_next)
    	{
    		do 
    		{
    			do_something(local_stuff);
    
    	case need_next:
    		    
    		        lock();
    			stuff_t local_stuff = unpack_next_stuff();
    			unlock();
    			
    		} while (!terminated && !zero_stuff);
    	}
    }
    
     
  9. Kandi

    Kandi Member

    Joined:
    18 Nov 2009
    Messages:
    344
    Likes Received:
    17
    Reputations:
    0
    Problems?, на сколько знаю с одного IP нельзя быстро слать, прокси узаешь?

    З.Ы. fail code :'(