Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Потоки и таймер ожидания


Автор: evgovs1991 8.12.2017, 14:39
Есть вот такая задача: 
Пользователь задает список, каждый элемент которого включает дату и время. Количество (пар дата / время) не ограничено.

Для каждого элемента списка создается отдельный 
поток, который в указанные пользователем дату и время открывает окно с сообщением о наступившем событии и ждет от пользователя подтверждения о прочтении. Если подтверждение не приходит в течение N секунд, то окно закрывается и повторно выдается через K секунд (N и K задаются в настройках). Если пользователь подтверждает прочтение, то поток разрушается и элемент удаляется из списка.
Для задания интервалов времени использовать таймеры ожидания.

Дату и время я храню в листбоксе. Написал функцию которая проверяет наступило событие или нет. Пытался сделать через компонент Timer создавая динамически таймер для каждого потока отслеживания но не получается...выводит одно событие максимум и при добавление потоков вылетает. Подскажите в каком направление действовать или алгоритм как это сделать.

Код

//создаю массив потоков
HANDLE *hThread = new [HANDLE];
//открываю поток и вызываю функцию потока
//хочу сделать цикл Timer для создания и проверка потока но программа ругается и вылетает
Button2Click(TObject *Sender)
{

hThread[counter] = CreateThread(0,0,EventThread,0,0,&dwThreadId);
counter++;
}
//функция потока
DWORD WINAPI EventThread(LPVOID lpParameter)
{
        CurrentTime=Time();
        CurrentDate=Date();
        AnsiString timeL = Form1->ListBox2->Items->Strings[counter];
        AnsiString dateL = Form1->ListBox1->Items->Strings[counter];
        AnsiString time = FormatDateTime("hh:mm:ss",CurrentTime.CurrentTime());
        AnsiString date = FormatDateTime("dd.MM.yyyy",CurrentDate.CurrentDate());
        if((date == dateL) && (time == timeL)){

            ShowMessage(counter);
        }
        Sleep(1);
        return 0;
}

Автор: xvr 8.12.2017, 15:36
VCL экранные элементы расчитанны на работу ТОЛЬКО из главного потока управления программы. Это во первых.

Во вторых - ваш поток (EventThread) проверяет, не совпала ли случайно дата и время из какого то (именно какого то, а не последовательного, как вы написали) элемента списка с текущим. Если да - то показывает сообщение. После чего немедленно завершается, не дожидаясь ничего. Это во вторых.

В третьих - Borland C++ Builder - это не Win API (на который намекает упоминание потоков и таймеров ожидания в задании)

В четвертых - 'подтверждения о прочтении' это не ShowMessage. Она не умеет закрываться по таймауту, как указано в задании.

Автор: evgovs1991 8.12.2017, 16:05
Цитата(xvr @ 8.12.2017,  15:36)
VCL экранные элементы расчитанны на работу ТОЛЬКО из главного потока управления программы. Это во первых.

Во вторых - ваш поток (EventThread) проверяет, не совпала ли случайно дата и время из какого то (именно какого то, а не последовательного, как вы написали) элемента списка с текущим. Если да - то показывает сообщение. После чего немедленно завершается, не дожидаясь ничего. Это во вторых.

В третьих - Borland C++ Builder - это не Win API (на который намекает упоминание потоков и таймеров ожидания в задании)

В четвертых - 'подтверждения о прочтении' это не ShowMessage. Она не умеет закрываться по таймауту, как указано в задании.

Программу надо сделать в embarcadero rad studio на Application Form.
Данные храняться у меня в контейнере list 
Код

struct TimeEvent{
    String dataEvent;
    String timeEvent;
};
list <TimeEvent> myList;
TimeEvent myEvent;


Суть задания в этом и есть добавил по нажатию кнопки задание в список,отображаю листбоксом для наглядности. Потом нажимаю пуск и должны открыть окна с сообщениями если совпала дата и время. Как мне контролировать время наступления события? Или чтобы поток вызывал Функцию каждую секунду? 

Автор: xvr 8.12.2017, 19:24
Если вам нужен именно отдельный поток и ожидание с помощью WaitableTimer, то вам нужно:
  •  Для каждого элемента из списка создать поток (через TThread). При создании записать в него сколько нужно ждать
  •  Внутри потока создать WaitableTimer, установить время ожидания и ждать (см https://msdn.microsoft.com/en-us/library/windows/desktop/ms687008(v=vs.85).aspx)
  •  По окончании вызвать callback из основного потока через функцию TThread::Synchronize
  •  Внутри этого callback'а создать и показать немодальную форму с сообщением, кнопкой и таймером. По нажатию кнопки форма закрывается и разрушается
  •  Если сработал таймер, то форма закрывается и разрушается, но перед этим вновь созда1тся поток (уже на K секунд)
Можно переиспользовать тот же самый поток, но это добавит массу кода для синхронизации между ним и формой с сообщением

Если отдельный поток не нужен, то это всё делается гораздо проще на обычных таймерах (TTimer)

Автор: evgovs1991 8.12.2017, 19:40
Цитата(xvr @ 8.12.2017,  19:24)
Если вам нужен именно отдельный поток и ожидание с помощью WaitableTimer, то вам нужно:

  •  Для каждого элемента из списка создать поток (через TThread). При создании записать в него сколько нужно ждать
  •  Внутри потока создать WaitableTimer, установить время ожидания и ждать (см https://msdn.microsoft.com/en-us/library/windows/desktop/ms687008(v=vs.85).aspx)
  •  По окончании вызвать callback из основного потока через функцию TThread::Synchronize
  •  Внутри этого callback'а создать и показать немодальную форму с сообщением, кнопкой и таймером. По нажатию кнопки форма закрывается и разрушается
  •  Если сработал таймер, то форма закрывается и разрушается, но перед этим вновь созда1тся поток (уже на K секунд)
Можно переиспользовать тот же самый поток, но это добавит массу кода для синхронизации между ним и формой с сообщением

Если отдельный поток не нужен, то это всё делается гораздо проще на обычных таймерах (TTimer)

Спасибо, попробую разобраться. В этом и загвостка что нельзя Timer использовать для N и К

Автор: XPyCT 10.12.2017, 00:55
Кто мешает создать свои собственный таймер?
Код

DWORD dwTime = timeGetTime();
int nDelay = 10; //Ваше значение


DWORD dwAttTime = 0;
...
if((dwAttTime +nDelay ) > dwTime  ){
return false;
}
dwAttTime  = nDelay + dwTime  ;

return true;


что то типо этого, естественно  оберните в функцию или метод класса и dwAttTime  вынесите в класс приватным инициализируйте  при старте в констукторе

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)