IPB
ЛогинПароль:

> Внимание!

1. Пользуйтесь тегами кода. - [code] ... [/code]
2. Точно указывайте язык, название и версию компилятора (интерпретатора).
3. Название темы должно быть информативным. В описании темы указываем язык!!!

 
 Ответить  Открыть новую тему 
> Синхронизация работы экземпляров приложения, VC++ 2008 EE
18192123
сообщение 7.11.2008 19:05
Сообщение #1


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Требуется разработать приложение, которое, будучи запущенным несколько раз, выполняет отчёт до 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
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 7.11.2008 20:02
Сообщение #2


Гость






Цитата
не пойму, что должно быть 3-им параметром в CreateThread
Это должна быть точка входа (адрес) в функцию, выполняемую потоком. То есть, говоря просто, в твоем случае это и будет та функция, которая должна будет досчитать до 5-ти, потом подождать все остальные потоки, и опять посчитать до 5-ти, и т.д...

DWORD WINAPI thread_func(LPVOID lpParam)
{
            // действия, выполняемые потоком
}

...
	    hThreadArray[i] = CreateThread( 
            NULL,                   
            0,
            thread_func, // передается вот так
            NULL,          
            0,               
            &dwThreadIdArray[i]);   
...
 К началу страницы 
+ Ответить 
18192123
сообщение 8.11.2008 13:38
Сообщение #3


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Теперь вопросы по сути задания...
В качестве метода синхронизации нужно использовать события (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);

}


 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 8.11.2008 15:37
Сообщение #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
сообщение 8.11.2008 21:54
Сообщение #5


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Прежде всего такой вопрос: в приведённом выше коде потоки(!) разрабатываемого приложения выполняют счёт друг за другом...по заданию нужно, чтобы экземпляры(!!) приложения этим занимались..тогда вопрос: значит ли, что выполняющиеся последовательно потоки есть те самые экземпляры приложения? или мы в потоках должны позаботиться о запуске экземпляра приложения?

Теперь по коду..
Вот создали мы объект-событие, оно занято (FALSE),
теперь в цикле создаются потоки...
насколько я поняла, при создании 1-го же потока мы переходим в функцию thread_func.. (или нет? и сначала всё потоки создаются??)
RunMore истина, заходим в цикл -
событие у нас занято (изначально), тогда WaitForSingleObject должна "усыпить" наш 1-й поток...Тогда какой поток считать будет? 2-й? но разве он уже создан? Вот тут запуталась..Объясните пожалуйста..!
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 8.11.2008 22:30
Сообщение #6


Гость






Цитата
значит ли, что выполняющиеся последовательно потоки есть те самые экземпляры приложения? или мы в потоках должны позаботиться о запуске экземпляра приложения?
Стоп... Возникает 2 вопроса:

1) если у тебя работа с копиями приложения, зачем ты начала делать это с потоками?
2) при работе с потоками у тебя все понятно и прозрачно: есть основной поток приложения, который запускает несколько дочерних потоков, и только потом ставит Event, разрешающий потокам работать. Как по-твоему это должно происходить при запуске нескольких копий приложения? Ну, вот запустила ты приложение первый раз, и что? что должно произойти? Ждать, пока будет запущена еще одна копия? Или приложение само должно вызывать CreateProcess для создания самого себя себя?

Короче говоря: кто инициатор запуска нескольких копий приложения? Первая копия? Или пользователь?

Цитата
насколько я поняла, при создании 1-го же потока мы переходим в функцию thread_func..
Ну, и что? Переходим. Но пока не было SetEvent, каждый из созданных потоков будет ждать в WaitForSingleObject, пока событие не будет установлено. А установлено оно будет только после создания всех потоков.
 К началу страницы 
+ Ответить 
18192123
сообщение 8.11.2008 22:46
Сообщение #7


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(volvo @ 8.11.2008 22:30) *

Стоп... Возникает 2 вопроса:

1) если у тебя работа с копиями приложения, зачем ты начала делать это с потоками?

с потоками для того, что бы можно было для синхронизации работы использовать Event (последнее диктуется заданием)..
Цитата(volvo @ 8.11.2008 22:30) *

2) .....
Короче говоря: кто инициатор запуска нескольких копий приложения? Первая копия? Или пользователь?


в задании это не обговаривается..так что я думаю, разработчик приложения сам это решает с точки зрения выбора наиболее разумного способа (а что разумнее: первая копия запускает остальные копии приложения или пользователь, я не знаю..)
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 8.11.2008 23:14
Сообщение #8


Гость






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

Цитата
а что разумнее: первая копия запускает остальные копии приложения или пользователь, я не знаю..
Я тем более не знаю. Решай. Я бы сделал запуск копий пользователем. Запущена одна копия - работает постоянно только она. Запустили вторую - работают первая и вторая поочередно, и т.д. Но вот тебе еще вопрос на засыпку: куда ты будешь выводить информацию о работе процесса? Каждый процесс - в свое окно? Тогда как следить за тем, что выполняются процессы именно в нужном порядке? Куда-нибудь в один из процессов? Тогда в какой именно?

Может, сделать первую копию с GUI, а все последующие уже без? То есть, окно будет только у первой копии, а все остальные будут работать с ним.
 К началу страницы 
+ Ответить 
18192123
сообщение 8.11.2008 23:32
Сообщение #9


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(volvo @ 8.11.2008 23:14) *

Решай. Я бы сделал запуск копий пользователем. Запущена одна копия - работает постоянно только она. Запустили вторую - работают первая и вторая поочередно, и т.д.
Может, сделать первую копию с GUI, а все последующие уже без? То есть, окно будет только у первой копии, а все остальные будут работать с ним.

Да, я согласна с тем, что запуск копий будет производиться пользователем

Цитата(volvo @ 8.11.2008 23:14) *

Может, сделать первую копию с GUI, а все последующие уже без? То есть, окно будет только у первой копии, а все остальные будут работать с ним.

Ух ты..! Не знала, что так можно...Согласна, что это очень удобный способ отслеживать очередность действия копий..Только, как сделать - не представляю..
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 9.11.2008 1:53
Сообщение #10


Гость






Цитата
Только, как сделать - не представляю
Что мешает тебе сделать следующее: прежде всего проверять через OpenMutex наличие своего мьютекса? (как запрещается запуск второй копии приложения, знаешь? Тот же принцип, но тебе надо не запретить, а отследить) Если его нет - то это первая копия приложения, так? Вот только тогда и регистрировать класс окна, создавать окно, и создавать мьютекс, который при запуске следующей копии уже будет существовать. Если же мьютекс уже существовал, то это - не первая копия, и окно создавать уже не надо...
 К началу страницы 
+ Ответить 
18192123
сообщение 9.11.2008 17:02
Сообщение #11


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(volvo @ 9.11.2008 1:53) *

..как запрещается запуск второй копии приложения, знаешь? Тот же принцип, но тебе надо не запретить, а отследить..


Не знаю, как это делается...Объясните пожалуйста..!

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 9.11.2008 17:14
Сообщение #12


Гость






В общем, задачка интересная, вот я набросал кое-что, тестировалось это в GCC, там все работает, лень запускать Студию smile.gif

Я не думаю, что будет очень много отличий... Возможно, что-то связанное с Юникодом опять всплывет, а так WinAPI он и в Африке WinAPI. Посмотри, как оно работает, я там прокомментировал кое-что, файл в кодировке UTF-8: Прикрепленный файл  main.cpp ( 6.35 килобайт ) Кол-во скачиваний: 497

 К началу страницы 
+ Ответить 
18192123
сообщение 9.11.2008 19:30
Сообщение #13


Профи
****

Группа: Пользователи
Сообщений: 920
Пол: Женский
Реальное имя: Марина

Репутация: -  2  +


Цитата(volvo @ 9.11.2008 17:14) *

В общем, задачка интересная, вот я набросал кое-что, тестировалось это в GCC, там все работает, лень запускать Студию smile.gif

Я не думаю, что будет очень много отличий... Возможно, что-то связанное с Юникодом опять всплывет, а так WinAPI он и в Африке WinAPI..

Спасибо большое!! Переделала под VS, всё работает как надо!
С отслеживанием запуска очередной копии разобралась,
но возник вопрос, связанный с установкой таймера для любой копии приложения - зачем это делается? чтобы ограничить повторение всей цепочки счёта по времени? или я не правильно поняла?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
volvo
сообщение 9.11.2008 19:46
Сообщение #14


Гость






Цитата
возник вопрос, связанный с установкой таймера для любой копии приложения - зачем это делается? чтобы ограничить повторение всей цепочки счёта по времени? или я не правильно поняла?
Не очень люблю отвечать вопросом на вопрос, но здесь именно так и сделаю: а где еще можно организовать этот цикл "счета", чтобы программа работала, и при этом еще и другие приложения не лишались "права голоса"? Чтобы во время работы твоей программы происходила обработка всех событий, получаемых окном? Таймер - оптимальный выход. Когда приложение получает WM_TIMER, оно занимается ожиданием события и "счетом", в остальное время приложение обрабатывает любые другие сообщения.
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 

- Текстовая версия 18.07.2025 9:21
Хостинг предоставлен компанией "Веб Сервис Центр" при поддержке компании "ДокЛаб"