![]() |
1. Пользуйтесь тегами кода. - [code] ... [/code]
2. Точно указывайте язык, название и версию компилятора (интерпретатора).
3. Название темы должно быть информативным.
В описании темы указываем язык!!!
![]() ![]() |
![]() |
18192123 |
![]()
Сообщение
#1
|
![]() Профи ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 920 Пол: Женский Реальное имя: Марина Репутация: ![]() ![]() ![]() |
Требуется разработать приложение, которое, будучи запущенным несколько раз, выполняет отчёт до 5-ти, затем ждёт, пока другой экземпляр этого приложения сосчитает до 5-ти, после чего продолжает свой отчёт. Счёт выполняют все запущенные экземпляры приложения по очереди..
Воть.. начала с того, что запускаю эти самые экземпляры в отдельных потоках..трудность на этом этапе в том, что не пойму, что должно быть 3-им параметром в CreateThread..Объясните пожалуйста!
#define MAX_THREADS 3
//........
HANDLE hThreadArray[MAX_THREADS];
DWORD dwThreadIdArray[MAX_THREADS];
TCHAR szFileName[260];
OPENFILENAME ofn;
LPCWSTR lpFilter=TEXT("Executive\0*.EXE\0");
ZeroMemory(&ofn,sizeof(OPENFILENAME));
ofn.lStructSize=sizeof(OPENFILENAME) ;
ofn.hwndOwner=hWndMain;
ofn.hInstance=NULL;
ofn.lpstrFile = szFileName;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFileName);
ofn.lpstrFilter = lpFilter;
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn) && i<=3 )
{
i++;
hThreadArray[i] = CreateThread(
NULL,
0,
//???,
NULL,
0,
&dwThreadIdArray[i]);
}
Сообщение отредактировано: 18192123 - 7.11.2008 19:06 |
volvo |
![]()
Сообщение
#2
|
Гость ![]() |
Цитата не пойму, что должно быть 3-им параметром в CreateThread Это должна быть точка входа (адрес) в функцию, выполняемую потоком. То есть, говоря просто, в твоем случае это и будет та функция, которая должна будет досчитать до 5-ти, потом подождать все остальные потоки, и опять посчитать до 5-ти, и т.д...DWORD WINAPI thread_func(LPVOID lpParam)
{
// действия, выполняемые потоком
}
...
hThreadArray[i] = CreateThread(
NULL,
0,
thread_func, // передается вот так
NULL,
0,
&dwThreadIdArray[i]);
...
|
18192123 |
![]()
Сообщение
#3
|
![]() Профи ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 920 Пол: Женский Реальное имя: Марина Репутация: ![]() ![]() ![]() |
Теперь вопросы по сути задания...
В качестве метода синхронизации нужно использовать события (Event)... Тогда в функцию, выполняемую потоком, я добавила OpenEvent (событие создаётся ранее) и перевод объекта-событие в занятое состояние... Теперь, как я полагаю, должен осуществляться процесс счёта и ожидание, пока остальные экземпляры посчитают..И главный вопрос: что вообще нужно понимать под "посчитает до 5-ти"?...И как должна выглядеть организация процесса последовательного счёта каждым экземпляром??
DWORD WINAPI thread_func(LPVOID lpParam)
{
TCHAR szFileName[260];
OPENFILENAME ofn;
LPCWSTR lpFilter=TEXT("Executive\0*.EXE\0");
ZeroMemory(&ofn,sizeof(OPENFILENAME));
ofn.lStructSize=sizeof(OPENFILENAME) ;
ofn.hwndOwner=hWndMain;
ofn.hInstance=NULL;
ofn.lpstrFile = szFileName;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFileName);
ofn.lpstrFilter = lpFilter;
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (!GetOpenFileName(&ofn))
{
MessageBox(hWndMain,TEXT("Error by open file"),TEXT("Error"),MB_ICONERROR);
return 0;
}
SetEvent(OpenEvent(EVENT_MODIFY_STATE,
FALSE,
TEXT("MyEvent")));
//??Считаем...??
//освободить событие??
return 1;
}
void OnClickButThreads(HWND hwnd)
{
RECT Rect;
GetClientRect(hwnd,&Rect);
HANDLE hThreadArray[MAX_THREADS];
DWORD dwThreadIdArray[MAX_THREADS];
HANDLE hEvent=CreateEvent(NULL,
TRUE,
TRUE,
TEXT("MyEvent"));
if (i<=MAX_THREADS)
{
i++;
hThreadArray[i] = CreateThread(
NULL,
0,
thread_func,
NULL,
0,
&dwThreadIdArray[i]);
}
CloseHandle(hEvent);
}
|
volvo |
![]()
Сообщение
#4
|
Гость ![]() |
Цитата Теперь, как я полагаю, должен осуществляться процесс счёта и ожидание, пока остальные экземпляры посчитают Правильно полагаешь.Цитата И главный вопрос: что вообще нужно понимать под "посчитает до 5-ти"? Ну вот именно это и понимать: локальная переменная в функции потока меняет значение от 0 до 4 (или от 1 до 5). Чтобы было видно, что она-таки его меняет, можно, скажем, выводить текущее её (переменной) значение в какой-нибудь listbox. Чтобы заодно удостовериться, что потоки не "накладываются" один на другой, то есть, что не происходит так: переменная потока_1 становится = 1; переменная потока_1 становится = 2; переменная потока_2 становится = 1; переменная потока_1 становится = 3 ... По условию это недопустимо. Пока один поток работает - остальные спят...Цитата И как должна выглядеть организация процесса последовательного счёта каждым экземпляром?? Вот... А теперь - самое интересное. Я не знаю, что ты там делаешь в потоке (в смысле, в том коде, который привела), но вот такой код:bool RunMore = true;
DWORD WINAPI thread_func(LPVOID lpParam)
{
int ID = *((int *)lpParam); // ID потока, чтобы было видно, какой из потоков пишет в hListBox
while(RunMore) {
WaitForSingleObject(myEvent, INFINITE);
char s[50] = {0};
for(int i = 0; i < 5; i++) {
// считаем и показываем, что что-то происходит
sprintf(s, "thread = %d; n = %d\0", ID, i);
SendMessage(hListbox, LB_ADDSTRING, NULL, (LPARAM)s);
}
SetEvent(myEvent);
}
return 0;
}
...
// Внимание: событие - с автосбросом, а не ручное, как было у тебя !!!
myEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
int counter[THRD_COUNT] = {1, 2, 3}; // Это можно сделать и программно, я делал для простоты
for(int i = 0; i < THRD_COUNT; i++) {
hThread[i] = CreateThread(NULL, 0, thread_func, (PVOID)&counter[i], 0, &dwThreadIdArray[i]);
}
SetEvent(myEvent);
...
заставляет последовательно выполняться все потоки до тех пор, пока по какой-то причине (скажем, нажатие кнопки, как сделал я) переменная RunMore не станет = false.Попробуй разобраться, что тут происходит, если не понятно - спрашивай. |
18192123 |
![]()
Сообщение
#5
|
![]() Профи ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 920 Пол: Женский Реальное имя: Марина Репутация: ![]() ![]() ![]() |
Прежде всего такой вопрос: в приведённом выше коде потоки(!) разрабатываемого приложения выполняют счёт друг за другом...по заданию нужно, чтобы экземпляры(!!) приложения этим занимались..тогда вопрос: значит ли, что выполняющиеся последовательно потоки есть те самые экземпляры приложения? или мы в потоках должны позаботиться о запуске экземпляра приложения?
Теперь по коду.. Вот создали мы объект-событие, оно занято (FALSE), теперь в цикле создаются потоки... насколько я поняла, при создании 1-го же потока мы переходим в функцию thread_func.. (или нет? и сначала всё потоки создаются??) RunMore истина, заходим в цикл - событие у нас занято (изначально), тогда WaitForSingleObject должна "усыпить" наш 1-й поток...Тогда какой поток считать будет? 2-й? но разве он уже создан? Вот тут запуталась..Объясните пожалуйста..! |
volvo |
![]()
Сообщение
#6
|
Гость ![]() |
Цитата значит ли, что выполняющиеся последовательно потоки есть те самые экземпляры приложения? или мы в потоках должны позаботиться о запуске экземпляра приложения? Стоп... Возникает 2 вопроса: 1) если у тебя работа с копиями приложения, зачем ты начала делать это с потоками? 2) при работе с потоками у тебя все понятно и прозрачно: есть основной поток приложения, который запускает несколько дочерних потоков, и только потом ставит Event, разрешающий потокам работать. Как по-твоему это должно происходить при запуске нескольких копий приложения? Ну, вот запустила ты приложение первый раз, и что? что должно произойти? Ждать, пока будет запущена еще одна копия? Или приложение само должно вызывать CreateProcess для создания самого себя себя? Короче говоря: кто инициатор запуска нескольких копий приложения? Первая копия? Или пользователь? Цитата насколько я поняла, при создании 1-го же потока мы переходим в функцию thread_func.. Ну, и что? Переходим. Но пока не было SetEvent, каждый из созданных потоков будет ждать в WaitForSingleObject, пока событие не будет установлено. А установлено оно будет только после создания всех потоков. |
18192123 |
![]()
Сообщение
#7
|
![]() Профи ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 920 Пол: Женский Реальное имя: Марина Репутация: ![]() ![]() ![]() |
Стоп... Возникает 2 вопроса: 1) если у тебя работа с копиями приложения, зачем ты начала делать это с потоками? с потоками для того, что бы можно было для синхронизации работы использовать Event (последнее диктуется заданием).. 2) ..... Короче говоря: кто инициатор запуска нескольких копий приложения? Первая копия? Или пользователь? в задании это не обговаривается..так что я думаю, разработчик приложения сам это решает с точки зрения выбора наиболее разумного способа (а что разумнее: первая копия запускает остальные копии приложения или пользователь, я не знаю..) |
volvo |
![]()
Сообщение
#8
|
Гость ![]() |
Цитата с потоками для того, что бы можно было для синхронизации работы использовать Event Event тоже можно использовать для межпроцессного взаимодействия, только надо делать это аккуратно...Цитата а что разумнее: первая копия запускает остальные копии приложения или пользователь, я не знаю.. Я тем более не знаю. Решай. Я бы сделал запуск копий пользователем. Запущена одна копия - работает постоянно только она. Запустили вторую - работают первая и вторая поочередно, и т.д. Но вот тебе еще вопрос на засыпку: куда ты будешь выводить информацию о работе процесса? Каждый процесс - в свое окно? Тогда как следить за тем, что выполняются процессы именно в нужном порядке? Куда-нибудь в один из процессов? Тогда в какой именно?Может, сделать первую копию с GUI, а все последующие уже без? То есть, окно будет только у первой копии, а все остальные будут работать с ним. |
18192123 |
![]()
Сообщение
#9
|
![]() Профи ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 920 Пол: Женский Реальное имя: Марина Репутация: ![]() ![]() ![]() |
Решай. Я бы сделал запуск копий пользователем. Запущена одна копия - работает постоянно только она. Запустили вторую - работают первая и вторая поочередно, и т.д. Может, сделать первую копию с GUI, а все последующие уже без? То есть, окно будет только у первой копии, а все остальные будут работать с ним. Да, я согласна с тем, что запуск копий будет производиться пользователем Может, сделать первую копию с GUI, а все последующие уже без? То есть, окно будет только у первой копии, а все остальные будут работать с ним. Ух ты..! Не знала, что так можно...Согласна, что это очень удобный способ отслеживать очередность действия копий..Только, как сделать - не представляю.. |
volvo |
![]()
Сообщение
#10
|
Гость ![]() |
Цитата Только, как сделать - не представляю Что мешает тебе сделать следующее: прежде всего проверять через OpenMutex наличие своего мьютекса? (как запрещается запуск второй копии приложения, знаешь? Тот же принцип, но тебе надо не запретить, а отследить) Если его нет - то это первая копия приложения, так? Вот только тогда и регистрировать класс окна, создавать окно, и создавать мьютекс, который при запуске следующей копии уже будет существовать. Если же мьютекс уже существовал, то это - не первая копия, и окно создавать уже не надо... |
18192123 |
![]()
Сообщение
#11
|
![]() Профи ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 920 Пол: Женский Реальное имя: Марина Репутация: ![]() ![]() ![]() |
|
volvo |
![]()
Сообщение
#12
|
Гость ![]() |
В общем, задачка интересная, вот я набросал кое-что, тестировалось это в GCC, там все работает, лень запускать Студию
![]() Я не думаю, что будет очень много отличий... Возможно, что-то связанное с Юникодом опять всплывет, а так WinAPI он и в Африке WinAPI. Посмотри, как оно работает, я там прокомментировал кое-что, файл в кодировке UTF-8: ![]() |
18192123 |
![]()
Сообщение
#13
|
![]() Профи ![]() ![]() ![]() ![]() Группа: Пользователи Сообщений: 920 Пол: Женский Реальное имя: Марина Репутация: ![]() ![]() ![]() |
В общем, задачка интересная, вот я набросал кое-что, тестировалось это в GCC, там все работает, лень запускать Студию ![]() Я не думаю, что будет очень много отличий... Возможно, что-то связанное с Юникодом опять всплывет, а так WinAPI он и в Африке WinAPI.. Спасибо большое!! Переделала под VS, всё работает как надо! С отслеживанием запуска очередной копии разобралась, но возник вопрос, связанный с установкой таймера для любой копии приложения - зачем это делается? чтобы ограничить повторение всей цепочки счёта по времени? или я не правильно поняла? |
volvo |
![]()
Сообщение
#14
|
Гость ![]() |
Цитата возник вопрос, связанный с установкой таймера для любой копии приложения - зачем это делается? чтобы ограничить повторение всей цепочки счёта по времени? или я не правильно поняла? Не очень люблю отвечать вопросом на вопрос, но здесь именно так и сделаю: а где еще можно организовать этот цикл "счета", чтобы программа работала, и при этом еще и другие приложения не лишались "права голоса"? Чтобы во время работы твоей программы происходила обработка всех событий, получаемых окном? Таймер - оптимальный выход. Когда приложение получает WM_TIMER, оно занимается ожиданием события и "счетом", в остальное время приложение обрабатывает любые другие сообщения. |
![]() ![]() |
![]() |
Текстовая версия | 18.07.2025 9:21 |