Многопоточность с использованием CreateThread [Delphi]

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by GlooK, 24 Oct 2009.

  1. GlooK

    GlooK Elder - Старейшина

    Joined:
    20 Apr 2007
    Messages:
    172
    Likes Received:
    53
    Reputations:
    10
    Нужна помощь в понимании потоков :)

    До этого момента писал софт однопоточный. Сейчас хочу научиться писать многопоточные программы.

    Как я понимаю есть несколько реализаций. Знаю что можно написать используя класс TThread и CreateThread (или как пишут, правильней через BeginThread).

    Интересует именно CreateThread.

    Есть например такой код:
    Code:
    program threads;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils,
      WinSock;
    
    const
    mstimeout = 10000;
    buffsize = 1024;
    
    var
    hSocket: TSocket;
    FData: string;
    
    function fWSRecv(wHost, wRequest: string):string;
    var
    wsData: TWSAData;
    hHost: PHostEnt;
    hAddr: TSockAddrIn;
    hTimeout: TTimeVal;
    iRead: integer;
    hData: string;
    hBuffer: array[0..buffsize] of char;
    begin
     WSAStartup($202, wsData);
     hSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     hHost := gethostbyname(PChar(wHost));
     hAddr.sin_family := AF_INET;
     hAddr.sin_port := htons(80);
     hAddr.sin_addr := pinaddr(hHost^.h_addr^)^;
     hTimeout.tv_usec := 0;
     hTimeout.tv_sec := mstimeout;
     setsockopt(hSocket, SOL_SOCKET, SO_RCVTIMEO, @hTimeout, sizeof(ttimeval));
     connect(hSocket, hAddr, SizeOf(hAddr));
     hData := '';
     Send(hSocket, wRequest[1], length(wRequest), 0);
     while (TRUE) do
     begin
      FillChar(hBuffer, SizeOf(hBuffer), 0);
      iRead := Recv(hSocket, hBuffer, length(hBuffer), 0);
      hData := hData + copy(hBuffer, 0, iRead);
      if (iRead <= 0) then break;
     end;
     CloseSocket(hSocket);
     WSACleanup;
     result := hData;
    end;
    
    begin
    
    FData := fWSRecv('google.ru',
    'GET /search?q=abc' + #13#10 +
    'Host: google.ru' + #13#10 +
    'User-Agent: Mozilla/5.0' + #13#10 +
    'Accept: text/html' + #13#10 +
    'Accept-Language: ru' + #13#10 +
    'Accept-Charset: windows-1251' + #13#10 +
    'Connection: close' + #13#10#13#10);
    
    Writeln;
    Writeln('Done!');
    readln;
    end.
    
    
    Как сделать его многопоточным?

    Я попробовал так:
    Code:
    program threads;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils,
      WinSock,
      [B]Windows[/B];
    
    const
    mstimeout = 10000;
    buffsize = 1024;
    
    var
    hSocket: TSocket;
    FData: string;
    [B]wsData: TWSAData;
    idThread: integer;
    HThread: array[0..20] of THandle;[/B]
    
    function fWSRecv(wHost, wRequest: string):string;
    var
    hHost: PHostEnt;
    hAddr: TSockAddrIn;
    hTimeout: TTimeVal;
    iRead: integer;
    hData: string;
    hBuffer: array[0..buffsize] of char;
    begin
    
     hSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     hHost := gethostbyname(PChar(wHost));
     hAddr.sin_family := AF_INET;
     hAddr.sin_port := htons(80);
     hAddr.sin_addr := pinaddr(hHost^.h_addr^)^;
     hTimeout.tv_usec := 0;
     hTimeout.tv_sec := mstimeout;
     setsockopt(hSocket, SOL_SOCKET, SO_RCVTIMEO, @hTimeout, sizeof(ttimeval));
     connect(hSocket, hAddr, SizeOf(hAddr));
     hData := '';
     Send(hSocket, wRequest[1], length(wRequest), 0);
     while (TRUE) do
     begin
      FillChar(hBuffer, SizeOf(hBuffer), 0);
      iRead := Recv(hSocket, hBuffer, length(hBuffer), 0);
      hData := hData + copy(hBuffer, 0, iRead);
      if (iRead <= 0) then break;
     end;
     CloseSocket(hSocket);
     result := hData;
    end;
    
    function fThread(ptr: pointer):integer;
    begin
    FData := fWSRecv('google.ru',
    'GET /search?q=abc' + #13#10 +
    'Host: google.ru' + #13#10 +
    'User-Agent: Mozilla/5.0' + #13#10 +
    'Accept: text/html' + #13#10 +
    'Accept-Language: ru' + #13#10 +
    'Accept-Charset: windows-1251' + #13#10 +
    'Connection: close' + #13#10#13#10);
    ExitThread(0);
    result := 0;
    end;
    
    begin
    [B]WSAStartup($202, wsData);
    
    for idThread := 0 to 10 do
    HThread[idThread] := CreateThread(nil, 0, @fThread, nil, 0, HThread[idThread]);[/B]
    
    [B]//WSACleanup;[/B]
    Writeln;
    Writeln('Done!');
    readln;
    end.
    
    Но запросы не отправляются.
    Имеет ли вообще данный код право на жизнь?
    Можно ли так свободно использовать функции в потоке?
    Если есть, дайте линки на исходники программ с использованием Winsock + CreateThread.
    --------------------------------------------------------------------
    Рабочий пример http://tdlite.ru/delphi/multithread/
     
    #1 GlooK, 24 Oct 2009
    Last edited: 30 Aug 2010
  2. Espectro

    Espectro New Member

    Joined:
    9 Nov 2008
    Messages:
    11
    Likes Received:
    1
    Reputations:
    0
    держи
    http://forum.sources.ru/index.php?showtopic=255212
     
  3. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    код почти нормальный, но
    1) если ты ничего больше с потоками делать не будешь, то сразу закрывай дискриптор потока, а не храни его в массиве
    2) прототип функции которая вызывает в потоке чуть другой.
    т.е. не function fThread(ptr: pointer):integer;
    а function fThread(ptr: pointer):dword; stdcall;
    3) после запуска потоков ты должен дождаться их завершения
    в твоем случае потоки запустятся, но прога сразу же завершит свою работу.
    Для таких вещей можно заюзать функцию WaitForMultipleObjects которая имеет вид;
    DWORD WaitForMultipleObjects(
    DWORD nCount, // кол-во хендлов
    const HANDLE* lpHandles, // адрес массива с хендлами
    BOOL bWaitAll, // TRUE - ожидать завершения всех, FALSE - хотябы одного
    DWORD dwMilliseconds // таймаут. ставиш INFINITE - бесконечно.
    );
     
  4. GlooK

    GlooK Elder - Старейшина

    Joined:
    20 Apr 2007
    Messages:
    172
    Likes Received:
    53
    Reputations:
    10
    1. Как закрыть дескриптор потока?
    2. Функция WaitForMultipleObjects должна выглядить так:
    WaitForMultipleObjects(количество_активных_потоков, HThread, TRUE, INFINITE)?
    Так? т.е. количество активных потоков в моем примере 10.
    Я правильно понял?
     
  5. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    1) CloseHandle - но т.к. ты юзаеш WaitForMultipleObjects то толжен делать после него закрытие.
    2) WaitForMultipleObjects вроде правильно
     
    1 person likes this.
  6. mr. ZetRikS

    mr. ZetRikS New Member

    Joined:
    17 Jul 2009
    Messages:
    45
    Likes Received:
    2
    Reputations:
    0
    http://narod.ru/disk/14455913000/%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B8.rar.html

    Вот исходничек... я когда то программил... помоему то, что нужно...
    Асинхронная работа...
     
    1 person likes this.
  7. >>serhio<<

    >>serhio<< New Member

    Joined:
    10 Feb 2009
    Messages:
    40
    Likes Received:
    0
    Reputations:
    0
    Плз отредактируйте две задачки на Pascale, а то постоянные ошибки достали:(!!!

    program chast1;
    uses crt;
    var a,y,x: real;
    b:=Pi;
    c:=2*Pi;
    dety:=Pi/4;
    y:=b;
    while y < = c do
    begin
    x:=1-2*cos(a*y)+ln(y);
    a:=ln(y)/ln(2);
    writeln(y,x,a);
    y:=y+dety;
    end;
    readln;
    end.

    program chast2;
    x,y,a,b,c,dety:real;
    i,n:integer
    begin
    b:=pi;
    c:=2*pi;
    det y:=pi/4;
    n:=trune ((c-b)/det y);
    for i:=0 to n do
    begin
    y:=b+(dety*i);
    a:=logln(y)/ln(2);
    x:=1-2*cos(a*y)+ln(y);
    writeln(x,a,y);
    end;
    readln;
    end.