Форум программистов, компьютерный форум, киберфорум
Visual C++
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.54/13: Рейтинг темы: голосов - 13, средняя оценка - 4.54
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
1

Многопоточность

24.09.2013, 01:23. Просмотров 2719. Ответов 10
Метки нет (Все метки)


Здрасьте!
Люди, на этом форуме нашел ценный ответ по реализации мультипотоковых программах.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <windows.h>
#include <process.h>
#include <stdio.h>
 
CRITICAL_SECTION cs;
int a[ 5 ];
 
void Thread( void* pParams )
{
    int i, num = 0;
 
    while ( TRUE )
    {
        EnterCriticalSection( &cs );
        for ( i = 0; i < 5; i++ ) a[ i ] = num;
        LeaveCriticalSection( &cs );
        num++;
    }
}
 
int main( void )
 
{ 
    InitializeCriticalSection( &cs );
    _beginthread( Thread, 0, NULL );
 
    while( TRUE )
    {
        EnterCriticalSection( &cs );
        printf( "%d %d %d %d %d\n", 
            a[ 0 ], a[ 1 ], a[ 2 ],
            a[ 3 ], a[ 4 ] );
        LeaveCriticalSection( &cs );
    }
    return 0;
}
Только вот не понимаю: Есть приложения, (посмотрел в Resource Monitor) которые используют аж до 137 потоков (threads). Но когда я смотрю на этот монитор справа, то там есть 8 CPU, как мне сказали - это есть 8 потоков, в каждом ядре по 2 потока (thread), хотя я чувствую, что либо я что-то напутал, либо тот, кто мне объяснял. В общем, у меня цель, чтобы мое приложение графическое (использую цпу чтобы изучить лучше С++) использовал весь процессор, а не только одно ядро из 8 показываемых, хотя у меня процессор Intel i7, в котором только 4 ядра. Спасибо заранее.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
24.09.2013, 01:23
Ответы с готовыми решениями:

Многопоточность
Имеется приложение на Си в VS 2008. Приложение может создать большое количество экземпляров...

Многопоточность
Мне нужно сделать класс, от которого можно наследовать ещё какой-нибудь класс с какой-то...

Многопоточность в MFC
Доброе время суток. Возник ряд вопросов, касающихся реализации многопточности на MFC. Поток создаю...

Простое приложение для MFC, использующее многопоточность
Прошу помочь написатьпростое использование многопоточности в mfc visual c++, все перечитал,написать...

10
Ушел с форума
Эксперт С++
16414 / 7389 / 1185
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
24.09.2013, 10:34 2
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Есть приложения, (посмотрел в Resource Monitor) которые используют аж до 137 потоков (threads). Но когда я смотрю на этот монитор справа, то там есть 8 CPU, как мне сказали - это есть 8 потоков, в каждом ядре по 2 потока (thread), хотя я чувствую, что либо я что-то напутал, либо тот, кто мне объяснял.
Термин "поток" давно уже перегружен своими значениями.
Есть поток выполнения (или программный поток), который создается функциями
наподобие _beginthreadex.
Также есть понятие потока в CPU, поддерживающих технологию Hyper-Threading (HT):
каждое ядро таких CPU разделено на два потока, если один стопорится, второй
перехватывает у него "эстафетную палочку".
И есть еще потоки ввода-вывода в C++ (iostream).

Диспетчер задач Windows (вкладка "Быстродействие") не делает разницы между CPU,
ядрами и HT-потоками, для него все они являются "логическими процессорами".
Например, в двухпроцессорной системе, где каждый процессор имеет 4 ядра с
поддержкой HT, диспетчер будет показывать 16 логических процессоров, так как
2 CPU x 4 ядра x 2 HT-потока = 16.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
В общем, у меня цель, чтобы мое приложение графическое (использую цпу чтобы изучить лучше С++) использовал весь процессор, а не только одно ядро из 8 показываемых, хотя у меня процессор Intel i7, в котором только 4 ядра.
Наиболее естественный способ использовать все ресурсы - это разбить вычислительную
задачу на количество потоков, равных количеству CPU/ядер, причем так, чтобы они не
мешали друг другу. Дополнительно можно "закрепить" каждый поток за своим ядром, хотя
обычно в этом нет необходимости, так как система сама по себе достаточно хорошо
планирует потоки (см. SetThreadAffinityMask).
2
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
24.09.2013, 14:11  [ТС] 3
Большое спасибо за полноценный ответ. Не могли бы вы показать на примере, как программа может использовать все CPU потоки. И честно говоря, как узнать в Resource Manager (или в чем-то другом), что программу обрабатывает именно два CPU потока? Resource Manager показывает, сколько логических потоков используется, но как узнать какой/какие CPU используются им. Могу, конечно смотреть на график, запустить программу и после этого наблюдать, в каких из CPU повысился уровень использования, но наверное есть более рациональный вариант.
0
Ушел с форума
Эксперт С++
16414 / 7389 / 1185
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
24.09.2013, 15:30 4
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Не могли бы вы показать на примере, как программа может использовать все CPU потоки
Для начала нужно определить количество логических процессоров.
Для этого следует вызвать функцию Get(Native)SystemInfo и заглянуть в
поле dwNumberOfProcessors структуры SYSTEM_INFO, которую она заполнит.
Ну а дальше, к примеру, можно создать количество потоков, равное этому
значению, и повесить каждый поток на отдельный логический процессор.
Это делается функцией SetThreadAffinityMask. Если потоки не будут
"спать" на wait-функциях, ждать завершения операций ввода-вывода или
конфликтовать за общие ресурсы, легко получить 100% загрузку CPU.

Не забудьте перед экспериментами убедиться, что с термопастой и
охлаждением процессора все в порядке

Цитата Сообщение от Pro100Tom Посмотреть сообщение
И честно говоря, как узнать в Resource Manager (или в чем-то другом), что программу обрабатывает именно два CPU потока?
Никак. Потоки переключаются системой очень часто, много раз в секунду.
Чтобы определить, какой CPU/ядро/поток какой задачей занят, нужно
мониторить их с очень высокой частотой.
2
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
24.09.2013, 16:06  [ТС] 5
Спасибо! А программа будет работать быстрее после реализации мультипоточности? Или поставим вопрос так: в теории должна ли программа работать быстрее?
0
Ушел с форума
Эксперт С++
16414 / 7389 / 1185
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
24.09.2013, 16:42 6
Это зависит от задачи, которую вы пытаетесь распараллелить, и
еще очень сильно от того, как именно это делается.
0
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
24.09.2013, 16:51  [ТС] 7
У меня такая программа: на событии wm_create открываю файл, в котором хранятся координаты вершин и их фэйсы.. И записываю это все в массивы переменных. А на wm_paint я создаю матрицу (transformation) (создаю именно в этой секции, потому что надо изменяю angle, который использую в rotation матрице). (Хотя, попытаюсь оптимизировать и не использовать матрицы, а просто перемножать буду, то что касается точек x и y.) В общем после создания матрицы, я пропускаю каждую вершину через нее, чтобы получить новое значение, и рисую линиями модель. Есть таймер, который изменяет значение переменной angle, которую я использую для создания rotation матрицы. В принципе пока что все. Следующий этап будет backface culling и clipping, а потом и lighting. Как такую программу логичнее было бы распределить по потокам?
0
Ушел с форума
Эксперт С++
16414 / 7389 / 1185
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
24.09.2013, 16:58 8
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Как такую программу логичнее было бы распределить по потокам?
Для начала определить "узкие места" - те, на выполнение которых уходит
больше всего активного процессорного времени. И подумать, поддаются ли
они распараллеливанию или нет. И нужно ли их вообще параллелить.

Потом обычно пишется "прототип", на котором обкатываются те или иные
решения по распараллеливанию и оптимизации. С опытом время на эту фазу
снижается (интуиция позволяет принимать наиболее подходящие решения).
Ну а потом все переписывается и рефакторится как надо.
1
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
25.09.2013, 19:55  [ТС] 9
Вроде бы нашел логичное место для использования мультипотоков. У меня есть вот такая программа:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
// New3DRenderer03_05_13.cpp : Defines the entry point for the application.
 
#include "stdafx.h"
#include "SpinningObjects.h"
#include "ModelClass.h"
#include "MatrixClass.h"
 
#define MAX_LOADSTRING 100
 
// Global Variables:
HINSTANCE hInst;                                // current instance
TCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
 
// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
 
int APIENTRY _tWinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPTSTR    lpCmdLine,
                       int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
 
    // TODO: Place code here.
    MSG msg;
    HACCEL hAccelTable;
 
    // Initialize global strings
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_SPINNINGOBJECTS, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);
 
    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }
 
    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SPINNINGOBJECTS));
 
    // Main message loop:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
 
    return (int) msg.wParam;
}
 
//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;
 
    wcex.cbSize = sizeof(WNDCLASSEX);
 
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SPINNINGOBJECTS));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_SPINNINGOBJECTS);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
 
    return RegisterClassEx(&wcex);
}
 
//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;
 
    hInst = hInstance; // Store instance handle in our global variable
 
    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
 
    if (!hWnd)
    {
        return FALSE;
    }
 
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
 
    return TRUE;
}
 
//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
int vCount, fCount, nCount;
VertexClass *vArray; 
FaceClass *vfArray;
FaceClass *nfArray;
VertexClass tempVertex[10000];
const int IDT_TIMER1 = 1;
float angle = 0.0f;
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc, bdc;
    HBITMAP backBuffer;
    RECT client;
    GetClientRect(hWnd, &client);
 
    switch (message)
    {
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // Parse the menu selections:
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_CREATE: 
        vCount = 0;
        fCount = 0;
        nCount = 0;
 
        ModelClass::GetModelData(&vCount, &fCount, &nCount);
 
        vArray = new VertexClass[vCount];
        vfArray = new FaceClass[fCount];
        nfArray = new FaceClass[fCount];
 
        ModelClass::LoadModel(vArray, vfArray, nfArray);
 
        for (int i = 0; i < fCount; i++)
        {
            tempVertex[i] = vArray[i];
            MatrixClass::BuildTransformationMatrix(&tempVertex[i].x, &tempVertex[i].y, &tempVertex[i].z, &angle);
        }
 
        SetTimer(hWnd, IDT_TIMER1, 40, 0);
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        hdc = GetDC(hWnd);
        bdc = CreateCompatibleDC(hdc);
        backBuffer = CreateCompatibleBitmap(hdc, client.right - client.left, client.bottom - client.top);
        SelectObject(bdc, backBuffer);
        SetDCBrushColor(bdc, RGB(0, 0, 0));
        Rectangle(bdc, client.left, client.top, client.right, client.bottom);
 
        // TODO: Add any drawing code here...
        for (int i = 0; i < fCount; i++)
        {
            tempVertex[i] = vArray[i];
            MatrixClass::BuildTransformationMatrix(&tempVertex[i].x, &tempVertex[i].y, &tempVertex[i].z, &angle);
 
            MoveToEx(bdc, tempVertex[vfArray[i].a - 1].x, tempVertex[vfArray[i].a - 1].y, false);
            LineTo(bdc, tempVertex[vfArray[i].b - 1].x, tempVertex[vfArray[i].b - 1].y);
 
            MoveToEx(bdc, tempVertex[vfArray[i].b - 1].x, tempVertex[vfArray[i].b - 1].y, false);
            LineTo(bdc, tempVertex[vfArray[i].c - 1].x, tempVertex[vfArray[i].c - 1].y);
 
            MoveToEx(bdc, tempVertex[vfArray[i].a - 1].x, tempVertex[vfArray[i].a - 1].y, false);
            LineTo(bdc, tempVertex[vfArray[i].c - 1].x, tempVertex[vfArray[i].c - 1].y);
        }
 
        BitBlt(hdc, client.left, client.top, client.right, client.bottom, bdc, 0, 0, SRCCOPY);
        DeleteObject(backBuffer);
        DeleteDC(bdc);
        ReleaseDC(hWnd, hdc);
        EndPaint(hWnd, &ps);
        break;
    case WM_TIMER: 
        switch (wParam) 
    case IDT_TIMER1: 
        angle += 1.0f;
        if (angle > 360.0f) 
            angle = 0.0f;
        InvalidateRect(hWnd, 0, false);
        break;
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
 
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;
 
    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}
Я подумал, что может стоит попробовать создать отдельный поток для таймера. Это логично? Помогите пожалуйста, я когда научусь, потом сам все делать буду. Мне только на первое время нужна помощь.
0
Заблокирован
Автор FAQ
25.09.2013, 23:34 10
Pro100Tom, для отрисовки достаточно вывести в отдельный поток отрисовку вот этого
Цитата Сообщение от Pro100Tom Посмотреть сообщение
case WM_PAINT:
Цитата Сообщение от Pro100Tom Посмотреть сообщение
for (int i = 0; i < fCount; i++)
* * * * {
* * * * * * tempVertex[i] = vArray[i];
* * * * * * MatrixClass::BuildTransformationMatrix(&tempVertex[i].x, &tempVertex[i].y, &tempVertex[i].z, &angle);
MoveToEx(bdc, tempVertex[vfArray[i].a - 1].x, tempVertex[vfArray[i].a - 1].y, false);
* * * * * * LineTo(bdc, tempVertex[vfArray[i].b - 1].x, tempVertex[vfArray[i].b - 1].y);
MoveToEx(bdc, tempVertex[vfArray[i].b - 1].x, tempVertex[vfArray[i].b - 1].y, false);
* * * * * * LineTo(bdc, tempVertex[vfArray[i].c - 1].x, tempVertex[vfArray[i].c - 1].y);
MoveToEx(bdc, tempVertex[vfArray[i].a - 1].x, tempVertex[vfArray[i].a - 1].y, false);
* * * * * * LineTo(bdc, tempVertex[vfArray[i].c - 1].x, tempVertex[vfArray[i].c - 1].y);
* * * * }
- если рисовать последовательно как это сделано сейчас окно просто будет подвисать на перерисовках и думаю вылетит в конечном итоге либо приложение будет работать "рывками" (ведь мы тормозим разбор очереди сообщений). Таймер делать в отдебном потоке глупо - ты же сам написал что нашёл код распараллелиавания по критической секции, кто же тебе мешает сделать синхронизацию в WM_TIMER величины angle с потоком отрисовки?

Добавлено через 1 минуту
Вот живой пример многопоточной консоли Как после обработки потока запустить его с новым методом?
1
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 389
26.09.2013, 02:35  [ТС] 11
Спасибо за совет. Я сделал так как вы посоветовали и все было так как вы сказали. Использовалось много потоков, и программа работала быстрее, чем до этого. Но в Visual Studio 2012 есть возможность запускать приложения при помощи GPU. Тогда multithreading не работает. Думаю, он только CPU поддерживается. И используя GPU все-таки работает быстрее чем используя multithreading. Но прикол в том, что у меня есть две видеокарты. Integrated Graphics 3000 и NVIDIA 540M. Но я не могу запустить приложения используя NVIDIA. Даже, если настраиваю в настройках. Но я и не уверен, что он использует Integrated Graphics потому что в Device Manager я ее отключал, перезагружаз комп, и использовал gpu для обработки приложения. Но все равно скорость была такая же. И в трее GPU Activity было пусто. У меня такое ощущение, что этот GPU, который в Visual Studio, он какой-то симулятор внутри CPU. В общем, подскажите, можно ли запустить Win 32 app при помощи GPU NVidia GeForce 540M? Если да, то скажите как. Спасибо!

Добавлено через 1 час 16 минут
Я вообщерискнул отключить обе и все равно есть изображение и все равно работает программа и использует какую-то "третью" GPU...
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.09.2013, 02:35

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь или здесь.

Многопоточность в Windows.Forms: вопрос реализации в общем
Всем добрый день. Только начинаю изучать с++, пользуюсь microsoft visual c++ 2010. возникла такая...

[Многопоточность] Как в функцию, которая будет выполняться в отдельном потоке, передать нужные аргументы?
Есть функция: UINT control1(LPVOID Param) { char msg;char pr=&quot;w&quot;; while(true){...

C++ Многопоточность
Как сделать так, чтобы эта программа заработала? А то она мне вот что пишет: g++ test.cpp -o...

Многопоточность и процессы
Начал изучать многопоточность и реализацию ее на плюсах. Посоветуйте толковую литературу с хорошими...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.