Страница: 1 | 2 | 3 | 4 | 5 |
|
Вопрос: Два ядра под VB6
|
Добавлено: 08.08.11 21:43
|
|
Номер ответа: 17 Автор ответа: Сергей Юдин
Вопросов: 8 Ответов: 81
|
Профиль | | #17
|
Добавлено: 12.08.11 06:27
|
Core i5 вообще-то 4-ядерный
Спасибо за ответ, но в моем рекламном проспекте написано, что Core i7 бывают 4\8 и 2\4, а Core i5 и Core i3 2\4, где числитель это число ядер, а знаменатель это число потоков. Спасибо также КаддафиМ и Smith за их реальный пример, но он мне кажется сложноватым в реализации, а у меня и так хватает заморочек с чисто математическим кодом программы. По этому хочу немного уточнить вопрос, т.к. мне не нужно хоть какое-нибудь теоретическое решение, а нужно надежное практическое решение. Ведь Стивен Роман в своей книге «Программирование в Win32 API наVisual Basic» четко пишет, что «Visual Basic не поддерживает создание потоков в приложениях (только в очень ограниченном виде с динамическими библиотеками и управляющими элементами ActiveX), не смотря на то, что API функция CreateThread в VB работает. Более того, так как создание и использование потоков требует особой осторожности, не рекомендуется создавать потоки в приложениях VB».
Так вот, у меня еще такие вопросы. Если мы создаем второй поток на двуядерном компьютере с помощью функции API CreateThread, то второй поток обязательно будет запущен на другом ядре или может быть тоже на первом ядре, где была запущена основная программа (ведь на одном ядре могут быть запущены два потока)? А, может быть, для надежной работы двух потоков надо запустить две разные программы, которые автоматически запустятся в разных потоках, т.е. на разных ядрах, а потом синхронизировать их работу с помощью функций API PostMessage и SendMessage, т.к. код во втором потоке должен начинать выполняться после комонды из первого потока, а потом доложить первому потоку, что он выполнен и ждать дальнейших указаний от первого потока. При этом и первый поток может отдавать команду второму потоку только после того, как второй поток выполнил свой цикл вычислений и отчитался об этом перед первым потоком.
А для более ясного понимания сути проблемы вкратце опишу, что я делаю и что хочу сделать. Имеется основная программа Main в которой я задаю начальные данные, затем, после решения системы 33 дифференциальных уравнений второго порядка (66 первого) в подпрограмме Diffur_main, я провожу в Main статистическую обработку и вывод на графики и в файл полученных в Diffur_main данных. А, после изменения в Main текущего смоделированного времени T1, я опять обращаюсь к подпрограмме Diffur_main и так несколько миллионов раз. Я бы хотел, чтобы программа Diffur_main работала постоянно (второй поток), т.к. это критичный код, а программа Main (первый поток) не отнимала у нее время на обработку данных и их вывод на экран и в файл.
Private Sub Main()
………………….
10 :T1=T1+P0
Diffur_main
…………….
Goto 10
End Sub
Private Sub Diffur_main()
………………
T2 = T1 ' метод Рунге-Кутта по 4-м коэффициентам
For k = 0 To N4: O(k) = Q(k): Next k
Diffur22
For k = 0 To N4: C1(k) = P0 * W(k): Q(k) = O(k) + C1(k) / 2: Next k
T2 = T1 + P0 / 2
Diffur22
For k = 0 To N4: C2(k) = P0 * W(k): Q(k) = O(k) + C2(k) / 2: Next k
Diffur22
For k = 0 To N4: C3(k) = P0 * W(k): Q(k) = O(k) + C3(k): Next k
T2 = T1 + P0
Diffur22
For k = 0 To N4: C4(k) = P0 * W(k): Next k
For k = 0 To N4: Q(k) = (C1(k) + 2 * C2(k) + 2 * C3(k) + C4(k)) / 6 + O(k): Next k
For i = 0 To Ne
X(i) = Q(i): Y(i) = Q(i + Ne + 1): Z(i) = Q(i + 2 * (Ne + 1)) 'делаем расшифровку переменных Next i
………………….
End Sub
Private Sub Diffur22()
W(0) = Q(33): ………………………….W(32) = Q(65)
W(33) = (FX(1, 0) + FX(2, 0) + FX(3, 0) + FX(4, 0) + FX(5, 0) + FX(6, 0) + FX(7, 0) + FX(8, 0) + FX(9, 0) + FX(10, 0)) / m(0)
…………............
W(65) = (FZ(0, 10) + FZ(1, 10) + FZ(2, 10) + FZ(3, 10) + FZ(4, 10) + FZ(5, 10) + FZ(6, 10) + FZ(7, 10) + FZ(8, 10) + FZ(9, 10)) / m(10)
End Sub
С наилучшими пожеланиями Сергей Юдин.
Ответить
|
Номер ответа: 18 Автор ответа: Ким Чен Ир
Вопросов: 0 Ответов: 140
|
Профиль | | #18
|
Добавлено: 12.08.11 10:51
|
Smith, я, упрощая код, проглядел. Если будешь использовать, то исправь в dll:
typedef long   __stdcall *funcptr)(long);
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
long ret = 0;
OleInitialize(NULL);
DWORD * psevdo = (DWORD*) lpParameter;
funcptr F = (funcptr) *(psevdo + 64);
long prm = *(psevdo + 65);
for (int i = 0; i < 64; i++)
TlsSetValue( i + 1, (LPVOID) *(psevdo + i));
try
{
ret =   *F)(prm);
}
catch(...)
{
MessageBox(0," Error in vb thread function!", 0,0);
}
free (psevdo);
for (DWORD i = 1; i < 65; i++)
TlsSetValue(i, NULL);
OleUninitialize();
return ret;
}
HANDLE __stdcall CreateVbThread(long start, DWORD param, DWORD flags )
{
DWORD * psevdo =(DWORD *) malloc(264);
for (int i = 0; i < 64; i++)
*(psevdo + i) = (DWORD) TlsGetValue(i+1);
if (*(psevdo + 39)) // МЫ В IDE ? sp6
*(psevdo + 5) = 0;
else
*(psevdo + 4) = 0;
*(psevdo + 64) = start;
*(psevdo + 65) = param;
DWORD trdid;
return CreateThread(0, 0, ThreadProc, (LPVOID) psevdo, flags, &trdid );
}
Ответить
|
Номер ответа: 19 Автор ответа: Ким Чен Ир
Вопросов: 0 Ответов: 140
|
Профиль | | #19
|
Добавлено: 12.08.11 12:06
|
Сергей Юдин, создавать несколько процессов под одну задачу, и синхронизировать их потоки, это на порядок сложнее и не даст особого выигрыша по времени исполнения. Планировщик потоков в системе итак выделяет текущему процессу больший квант времени, чем фоновым процессам. Можно поиграться с уровнями приоритета потоков. Привязывать поток к определенному ядру тоже сомнительно. Это вмешательство в нормальную работу планировщика. Правильнее указать желаемый процессор с помощью SetThreadIdealProcessor.
Для синхронизации потоков есть десятки функций. Начиная с юзермодных критических секций до ядерных семафоров. Но все они тебе без пользы, ведь ты веришь Стивену Роману , что бейсик не поддерживает многопоточность.
Я, правда, читал только Стивена Кинга, но он тоже врет как Троцкий.
Ты уж определись.
Ответить
|
Номер ответа: 21 Автор ответа: Ким Чен Ир
Вопросов: 0 Ответов: 140
|
Профиль | | #21
|
Добавлено: 12.08.11 17:56
|
Состояние слотов TLS текущего потока в IDE и в скомпилированном варианте разное.
Да, вместо смайлов скобка (
Ответить
|
Номер ответа: 23 Автор ответа: Ким Чен Ир
Вопросов: 0 Ответов: 140
|
Профиль | | #23
|
Добавлено: 12.08.11 20:06
|
Я даже теряюсь, не зная, как-бы популярнее объяснить...
Не претендуюя на полноту изложения...
Вот есть процесс. Его породилила операционная система при запуске исполняемого файла.
Процесс это условно просто структура в памяти, он ничего не делает. Одновременно с процессом порождается главный поток.
Он пока один и принадлежит процессу. Из главного потока можно создать еще потоки, они будут также принадлежать этому процессу.
У каждого созданного потока есть своя структура CONTEXT. Системный планировщик, исходя из своей внутренней логики и приоритета потока, переключает процессор на поток, а именно записывает в структуру CONTEXT предыдущего потока состояние всех своих регистров, а затем заливает в свои регистры контекст нового потока. Каждому процессу система выделяет отдельную память(адресное пространство) и все потоки одного процесса могут ее читать и писать. Вот под синхронизацией в первую очередь и понимается обеспечение целостности данных адресного пространства одного процесса.
Многопоточность и многозадачность - несколько разные вещи. Ты, как я понял хочешь зачем-то порождать несколько процессов под одну задачу.
Ответить
|
Номер ответа: 24 Автор ответа: Сергей Юдин
Вопросов: 8 Ответов: 81
|
Профиль | | #24
|
Добавлено: 13.08.11 07:37
|
Каждому процессу система выделяет отдельную память(адресное пространство) и все потоки одного процесса могут ее читать и писать. Вот под синхронизацией в первую очередь и понимается обеспечение целостности данных адресного пространства одного процесса.
Я так понял, что Вы говорите об одноядерных процессорах, где потоки запускаются в одном процессе, чтобы иметь доступ к общей памяти этого процесса. Но я читал, что в многоядерных процессорах все ядра используют общую память и, следовательно, можно получить для двух задач, работающих на разных ядрах, общее адресное пространство. Вот это то меня и прельщает в многоядерных процессорах, а если этого нет, то какая от них польза.
С наилучшими пожеланиями Сергей Юдин.
Ответить
|
Номер ответа: 25 Автор ответа: Artyom
Разработчик
Вопросов: 130 Ответов: 6602
|
Профиль | | #25
|
Добавлено: 13.08.11 08:47
|
Сергей Юдин, у тебя какая-то каша в голове. Почитай у Руссиновича в чем состоит суть многопоточности в Windows.
На многоядерных процессорах (и на многопроцессорных компьютерах) все работает почти так же как и на одноядерных. Основные отличия состоят в том, что
1) Несколько потоков могут выполняться реально одновременно на двух разных ядрах (а не по очереди). Планировщик сам распределяет потоки по ядрам, AffinityMask трогать нужно очень редко. Таким образом на определенных задачах при правильной реализации можно получить реальное увеличение быстродействия прямо пропорциональное увеличению кол-ва ядер. А также можно не получить вообще никакого увеличения быстродействия, зато в большей степени начнут себя проявлять допущеные multithreading-specifig баги.
2) На ядре есть своя кеш-память, не связанная с кеш-памятью других ядер (кроме того может быть и общая кеш-память). Поэтому применяются специальные механизмы, препятствующие возникновению ситуаций когда на разных ядрах в кеш-память попадают одни и те же адреса памяти, что приведет к очень непредсказуемым результатам. Посмотри про NUMA если интересно. Программистам обычно этого знать не надо.
Все остальные особенности многопоточности (внезапно проблем гораздо больше чем преимуществ, даже если писать на дотнете, имеющим хорошие инструменты написания многопоточных приложений) будут в примерно равной степени проявляться и на одноядерном и на многоядерном компьютере. А это доступ (как правило на модификацию) к общим ресурсам, дедлоки, проблемы синхронизации, гонки потоков и т.п.
Почти все проблемы очень нестабильно себя проявляют. Это может зависеть от условий сборки (debug ошибки нет, release есть, или наоборот), версии фреймворка (если на дотнете пишешь), архитектуры процессора, фазы луны
Проблемы сложны в выявлении. Даже если видно что результаты работы некорректные, и есть подозрение, что дело в многопоточном коде, практически нет возможности воспроизвести эту проблему в отладчике, так как условия и тайминги будут отличаться, и код сработает уже по другому, может без ошибки, может с другой ошибкой.
Будут сложности в отладке (и я говорю про .NET и Visual Studio, а не про VB6) по сравнению с отладкой одного потока.
Помимо собственно возможности запустить несколько потоков (мечта которую VB6-ники видят в каждом сне) понадобятся еще некоторые вещи, а именно
* Нормальные средства отладки, хотя бы не рушащиеся на брейкпоинте
* Средства синхронизации (если kernel mode синхронизацию еще можно замутить на VB6 через функции Win32API, то user mode по-моему будет невозможно ввиду отсутствия возможности выполнять атомарные операции)
* Собственно атомарные операции (операции которые выполняются за 1 такт процессора и не могут быть прерваны на самом интересном месте другой операцией)
* Инструменты, упрощающие разработку многопоточных приложений (TPL в дотнете и не знаю что в С++ и других платформах).
Вобщем, это хорошая штука, пока речь идет о полностью изолированном потоке, не использующим общие ресурсы. Когда появляются общие ресурсы, появляются проблемы и потребность в прямых руках и правильно настроеных мозгах. Ибо решить их можно полностью моделируя в голове процесы которые происходят.
PS Напомнило рассказ Эпплмана о том как он на конференции спросил
- Кто хочет чтоб в VB6 появилась свободная потоковая модель?
Весь зал поднял руки
- А кто понимает что реально значит свободная потоковая модель?
Подняли руки несколько человек.
Ответить
|
Номер ответа: 27 Автор ответа: Ким Чен Ир
Вопросов: 0 Ответов: 140
|
Профиль | | #27
|
Добавлено: 13.08.11 16:31
|
надо запустить второй поток или как DLL библиотеку, которая не будет иметь общей памяти с основной программой
Сергей Юдин, повторюсь, поток принадлежит процессу и все потоки процесса имеют общее адресное пространство. Как ты думаешь, какому процессу будет принадлежать поток в dll?
Ответить
|
Номер ответа: 29 Автор ответа: Сергей Юдин
Вопросов: 8 Ответов: 81
|
Профиль | | #29
|
Добавлено: 13.08.11 21:00
|
Сергей Юдин, повторюсь, поток принадлежит процессу и все потоки процесса имеют общее адресное пространство. Как ты думаешь, какому процессу будет принадлежать поток в dll?
Получается, что процессу, который был создан основной программой в первом потоке. А, т.к. VB6 поддерживает создание потоков для DLL с помощью функции API CreateThread, то у них будет общее адресное пространство, даже, если второй поток будет запущен на втором ядре (только как сделать, чтобы он не запустился на первом ядре). А следовательно почти все упрощается и в DLL можно будет передавать массив данных по ссылке, т.е. получается полный хэппи энд.
С наилучшими пожеланиями Сергей Юдин.
Ответить
|
Номер ответа: 30 Автор ответа: Ким Чен Ир
Вопросов: 0 Ответов: 140
|
Профиль | | #30
|
Добавлено: 13.08.11 21:25
|
Прогресс в мыслях налицо.
Следующий наводящий вопрос, как потоку в dll после обработки неких данных вернуть результат вычислений в основной поток(тот который в exe)?
Ответить
|
Страница: 1 | 2 | 3 | 4 | 5 |
Поиск по форуму