Вопрос по потокам

Тема в разделе "MS Visual C++", создана пользователем Gwyllum, 12 апр 2010.

Статус темы:
Закрыта.
  1. Gwyllum

    Gwyllum Гость

    Суть моей программы - показать, что распараллеливание программы на двухъядерном процессоре способно увеличить скорость вычислений. Программа довольно проста - есть массив из 12 элементов. Программа сперва вычисляет значение каждого. Затем вычисления проводятся с помощью одного процесса. Затем массив разбивается на две части, каждую из которых вычисляют два процесса. Затем на три, на четыре, шесть и двенадцать. Программа замеряет время и строит график.
    Как оказалось, время вычисления на двухядернике одним потоком, занимает больше времени, чем обычным кодом. При разбиении на два процесса, это время уменьшается, но при трех - немного увеличивается и т.п. По идее, при вычислении на одноядерном процессоре, разбиение на два потока должно занять больше времени, чем обычное, т.к. тратится дополнительное время на открытие потоков и т.п. Но, результаты приблизительно такие-же.
    Подскажите, может в потоках используются какие-то ускоряющие вычисления методы или просто где-то в коде моем ошибка? Пожалуйста, не судите за качество кода - я еще новичок :)

    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">код</div></div><div class="sp-body"><div class="sp-content">
    Код (C++):
    #define ITER 999999
    double result[12];
    LPVOID atr[2];
    DWORD time[7];
    DWORD coords[7];
    DWORD maxTime;
    DWORD WINAPI Calculate(LPVOID value)// function calculate all values
    {
    int x=11;
    int number=(int)atr[1];

    for (int j=(int)value*number; j<(int)value*number+number; j++)
    {
    for (int i=0; i<ITER; i++)
    {
    result[j]=result[j]+(sqrt(sin((double)x)+cos((double)x ))-sqrt(acos((double)x)+asin((double)x )) );

    }
    }

    return 0;
    }
    LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    {
    PAINTSTRUCT ps;
    HDC hdc;
    switch(msg)
    {
    case WM_CREATE:
    {

    return 0;
    }break;
    case WM_DESTROY:
    {
    PostQuitMessage(0);
    return 0;

    }break;

    case WM_PAINT:
    {
    InvalidateRect(hwnd, NULL, FALSE);
    hdc=BeginPaint(hwnd, &ps);
    SelectObject(hdc, penWhite);
    SetTextColor(hdc, RGB(255,255,255));
    SetBkColor(hdc, RGB(0,0,0));
    TextOut(hdc, 20,30,(LPCWSTR)szTitle,6);
    MoveToEx(hdc, 50,700, NULL);
    LineTo(hdc, 50,50);
    MoveToEx(hdc, 50,700, NULL);
    LineTo(hdc, 950,700);
    for (int i=0; i<7; i++)
    {
    Ellipse(hdc,i*150+45,693,i*150+45+1 0,703);
    }
    SelectObject(hdc, penGray);

    for (int i=1; i<7; i++)
    {
    MoveToEx(hdc, i*150+50, 700, NULL);
    LineTo(hdc, i*150+50,50);
    }
    SelectObject(hdc, penGreen);
    MoveToEx(hdc, 50, 750-coords[0], NULL);
    for (int i=0; i<7; i++)
    {

    LineTo(hdc, i*150+50,750- coords[i]);
    }
    EndPaint(hwnd, &ps);
    DeleteObject(penWhite);
    return 0;
    }break;

    default: break;
    }

    return (DefWindowProc(hwnd, msg, wparam, lparam));
    }
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpcmdline, int ncmdshow)
    { HANDLE thread0;
    HANDLE thread2[2];
    HANDLE thread3[3];
    HANDLE thread4[4];
    HANDLE thread6[6];
    HANDLE thread12[12];
    DWORD thread_id[27];
    for (int i=0; i<12; i++)
    {
    result[i]=1;
    }
    int x=11;
    DWORD startTime=GetTickCount();//get start time
    for (int j=0; j<12; j++)
    {
    for (int i=0; i<ITER; i++)
    {

    result[j]=result[j]+(sqrt(sin((double)x)+cos((double)x ))-sqrt(acos((double)x)+asin((double)x )) );

    }
    }
    time[0]=GetTickCount()-startTime;// calculate time running
    atr[0]=LPVOID(1);
    atr[1]=LPVOID(12);
    for (int i=0; i<12; i++)
    {
    result[i]=1;
    }
    startTime=GetTickCount();
    thread0=CreateThread(NULL, 0, Calculate, (LPVOID)0, 0, &thread_id[0]);
    WaitForSingleObject(thread0, INFINITE);
    CloseHandle(thread0);
    time[1]=GetTickCount()-startTime;
    atr[0]=LPVOID(2);
    atr[1]=LPVOID(6);

    for (int i=0; i<12; i++)
    {
    result[i]=1;
    }
    startTime=GetTickCount();
    for (int i=0; i<(int)atr[0]; i++)
    {
    thread2[i]=CreateThread(NULL, 0, Calculate, (LPVOID)i, 0, &thread_id[i+1]);
    }
    WaitForMultipleObjects(2, thread2, TRUE, INFINITE);
    for (int i=0; i<(int)atr[0]; i++)
    {
    CloseHandle(thread2[i]);
    }
    time[2]=GetTickCount()-startTime;
    atr[0]=LPVOID(3);
    atr[1]=LPVOID(4);
    for (int i=0; i<12; i++)
    {
    result[i]=1;
    }
    startTime=GetTickCount();
    for (int i=0; i<(int)atr[0]; i++)
    { thread3[i]=CreateThread(NULL, 0, Calculate, (LPVOID)i, 0, &thread_id[i+3]);
    }
    WaitForMultipleObjects(3, thread3, TRUE, INFINITE);
    for (int i=0; i<(int)atr[0]; i++)
    {
    CloseHandle(thread3[i]);
    }
    time[3]=GetTickCount()-startTime;
    atr[0]=LPVOID(4);
    atr[1]=LPVOID(3);

    for (int i=0; i<12; i++)
    {
    result[i]=1;
    }
    startTime=GetTickCount();
    for (int i=0; i<(int)atr[0]; i++)
    {
    thread4[i]=CreateThread(NULL, 0, Calculate, (LPVOID)i, 0, &thread_id[i+6]);
    }
    WaitForMultipleObjects(4, thread4, TRUE, INFINITE);
    for (int i=0; i<(int)atr[0]; i++)
    {
    CloseHandle(thread4[i]);
    }
    time[4]=GetTickCount()-startTime;
    atr[0]=LPVOID(6);
    atr[1]=LPVOID(2);

    for (int i=0; i<12; i++)
    {
    result[i]=1;
    }
    startTime=GetTickCount();
    for (int i=0; i<(int)atr[0]; i++)
    {
    thread6[i]=CreateThread(NULL, 0, Calculate, (LPVOID)i, 0, &thread_id[i+10]);
    }
    WaitForMultipleObjects(6, thread6, TRUE, INFINITE);
    for (int i=0; i<(int)atr[0]; i++)
    {
    CloseHandle(thread6[i]);
    }
    time[5]=GetTickCount()-startTime;
    atr[0]=LPVOID(12);
    atr[1]=LPVOID(1);

    for (int i=0; i<12; i++)
    {
    result[i]=1;
    }
    startTime=GetTickCount();
    for (int i=0; i<(int)atr[0]; i++)
    {
    thread12[i]=CreateThread(NULL, 0, Calculate, (LPVOID)i, 0, &thread_id[i+15]);
    }
    WaitForMultipleObjects(12, thread12, TRUE, INFINITE);
    for (int i=0; i<(int)atr[0]; i++)
    {
    CloseHandle(thread12[i]);
    }
    time[6]=GetTickCount()-startTime;

    maxTime=0;
    for (int i=0; i<7; i++)
    {
    if (maxTime<time[i])
    {
    maxTime=time[i];
    }
    }

    for (int i=0; i<7; i++)
    {
    coords[i]=(time[i]*700)/maxTime;
    }

    hwnd=CreateWindowEx(NULL, WINDOW_CLASS_NAME, szTitle, WS_VISIBLE|WS_OVERLAPPED, 0,0,1024,768, NULL, NULL, hInstance, NULL);
    while( GetMessage(&msg, NULL, 0, 0))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }

    return msg.wParam;
    }
     
  2. Odin_KG

    Odin_KG Гость

    Gwyllum
    Насколько я помню, от того, что вы создадите в программе второй поток, второе ядро его выполнять не начнет. Т.е. все ваши потоки будут выполняться на одном ядре. А, чтобы подключить к потоку другое ядро, нужно использовать функцию: SetThreadAffinityMask

    Я код не смотрел, но массив или не массив это не важно - лишь бы не было одновременного обращения нескольких потоков в один и тот же байт памяти. Причем читать одновременно можно - проблема только с записью. Т.е. если один поток работает с первым элементом массива, а второй со вторым, то конфликта нет.
     
  3. Gwyllum

    Gwyllum Гость

    Нет) каждый поток обращается к своей части массива. За подсказку с функцией огромное вам спасибо! :D
     
  4. zeus

    zeus Гость

    Ваша программа не сможет показать реальные параллельные вычисления))) почему? потому что вы забываете про 0й поток, в котором работает оконная процедура, т.е теоретически 1й поток у вас будет выполняться на одном ядре, а 2й будет делить время с 0м потоком, которые оба выполняются на втором ядре (или наоборот, не суть...)

    Пишите консольные программы, в которых не нужно создавать окно, и выводите результаты в файл или на консоль )))
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">пример</div></div><div class="sp-body"><div class="sp-content">
    Код (C++):
    #include <windows.h>
    #define NUM 100

    void calc(int *res)
    {
    ...
    } // calc

    DWORD WINAPI thread(LPVOID val)
    {
    calc((int *)val);
    return 0;
    } // thread

    int main(void)
    {
    int res[2][NUM];

    HANDLE hThread = CreateThread(NULL, 0, thread, (LPVOID)res[0], 0, NULL);

    calc(res[1]);

    WaitForSengleObject(hThread, TRUE, INFINITE);
    CloseHandle(hThread);

    return 0;
    } // main
     
  5. Gwyllum

    Gwyllum Гость

    Вы совершенно правы, но, если вычисляется сложная тригонометрическая формула, причем многократно, то время ее вычисления во много раз превышает время работы оконной процедуры. Таким образом, чем больше цикл,тем меньше будет влиять время выполнения оконной процедуры. Тем более, что сперва вычисляются все значения и только потом создается окно :D Но, все равно, спасибо большое, лучше и правда начать с консоли :)
     
  6. Odin_KG

    Odin_KG Гость

    Пожалуйста :)

    А вообще zeus, наверное, прав - лучше напишите консольное приложение, так с потоками проще скорости померить.
     
  7. Gwyllum

    Gwyllum Гость

    Прошу прощения, немного не разобрался... SetThreadAffinityMask назначает какому-то ядру процессора поток? А как узнать, на каком ядре нам нужно выполнять процесс?
     
Загрузка...
Похожие Темы - Вопрос по потокам
  1. ApplePen
    Ответов:
    0
    Просмотров:
    55
  2. gURaBA_N
    Ответов:
    3
    Просмотров:
    91
  3. kartaman
    Ответов:
    0
    Просмотров:
    126
  4. Peter
    Ответов:
    4
    Просмотров:
    519
  5. di0d_
    Ответов:
    1
    Просмотров:
    433
Статус темы:
Закрыта.

Поделиться этой страницей