Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > В обход Sleep (ms) и for (;;)


Автор: zhgutov 11.4.2006, 13:21
Подскажите, можно ли сделать так, чтобы функция вызывалась, скажем, каждые 2 мс, но при этом проц не грузился на «все 100»?

Автор: _hunter 11.4.2006, 13:41
ищи по форуму.
заранее могу сказать -- никак не получится

Автор: zhgutov 11.4.2006, 13:55
Я уже поискал. Нашел только то, что не получится. Эээ... Винда, блин.

Автор: Fixin 11.4.2006, 14:07
А чем sleep и for неустраивают?
Код

for (;;)
{
    Func();
    Sleep(2);
}

Автор: zhgutov 11.4.2006, 14:19
Оно сейчас так и работает. Ситуация похожа на ту, которую ты говорил поискать. У меня в другом потоке графики рисуются. Устройство работает через COM и USB. С USB все в порядке, но COM все вешает. Сигнальные линии в COM не задействованы, событие повесить не могу. Посему хочу найти именно такой способ. К тому же на будущее полезно.

Автор: _hunter 11.4.2006, 14:21
Fixin, этот способ не подходит еще по одной причине -- Sleep имеет дискретность в 10 мс

Автор: VectorMan 11.4.2006, 14:27
а WaitForSingleObject не подходит? ещё можно заюзать timeSetEvent

Автор: zhgutov 11.4.2006, 14:33
WaitForSingleObject не к чему прикрутить, а про timeSetEvent я не знал, попробую...

Автор: VectorMan 11.4.2006, 14:59
Цитата(zhgutov @ 11.4.2006, 14:33)
WaitForSingleObject не к чему прикрутить,

а так?

Код

event = CreateEvent(NULL, FALSE, FALSE, NULL);

for(;;)
{
  WaitForSingleObject(event, 2);
  MyFunction();
}


хотя наверное у этой функции тоже есть какие то ограничения по точности

Автор: _hunter 11.4.2006, 15:05
есть. причем полностью аналогичные ограничениям Sleep' а

Автор: Fixin 11.4.2006, 15:20
Это ограничение существует из-за ограничений самой винды (ее архитектуры), можно только искуственные методы, с которыми я не знаком

Автор: zhgutov 11.4.2006, 15:38
Она почему-то тормозит. Очень сильно тормозит. Может я что делаю не так?
Код

void CALLBACK timer_callback (UINT uTimerID, UINT uMsg, DWORD_PTR timer_ptr, DWORD_PTR dw1, DWORD_PTR dw2)
{
    Timer& timer = *cast <Timer*>(timer_ptr);
    timer.activate ();
}

// ...

bool Timer::get_ready ()
{
    return id = timeSetEvent (delay, accuracy, timer_callback, cast <DWORD_PTR>(this), TIME_PERIODIC);
}

// ...

Автор: Fixin 11.4.2006, 15:47
Создание объекта и преобразование тпов - не быстрая операция

Автор: zhgutov 11.4.2006, 15:57
Объект там не создается и тип не преобразуется (unsigned -> void*). Временной интервал — 50 мс. Пробовал разные значения интервала и точности. Все-равно тормозит. Параллельно работает поток отображения всяких там графиков, проц грузится на 15 %, но тормозит (50 мс -> ~0.5 с)!

Автор: VectorMan 11.4.2006, 15:57
Цитата(zhgutov @ 11.4.2006, 15:38)
Она почему-то тормозит. Очень сильно тормозит.

в MSDN настоятельно рекомендуют перед использованием функций семейства time* устанавливать точность таймера через timeBeginPeriod (и соответственно после окончания работы использовать timeEndPeriod)

Автор: zhgutov 11.4.2006, 16:20
И это делаю, результат тот же.

Автор: zhgutov 17.4.2006, 10:06
Все, нашел! Работает корректно, алгоритм надо было изменить. 

Автор: Олег_Игоревич 24.4.2006, 21:33
Необходимо разработать драйвер.
Муторно но работать будет на 100%. 

Автор: takedo 25.4.2006, 08:02
zhgutov, так непонятно, неужели получилось вызывать таймер с периодом 2 миллисекунды в не RealTime операционке? Если да, то надо это обязательно в фак запихать.  

Автор: zhgutov 26.4.2006, 13:34
Я не измерял. Могу провести исследование на эту тему... Мне необходимо было сделать таймер с периодом 50 мс, а про 2 мс я написал для того, чтобы найти здесь такой способ, не более. Если б написал как есть, подозреваю, что меня бы послали в поиск. Посему так. О результатах скоро напишу. 

Автор: zhgutov 26.4.2006, 14:29
Вот, можете сами проверить, построить распределение вероятностей... Вроде компилируется.
Код
// main.cpp
#include <cstdio>
#include <timer.hpp>

class X: public Timer
{
    __int64 tick;
    double ms_max;
    int out, count;
public:
    X ();
    void activate ();
    ~X ();
};

void main ()
{
    init_timer ();
    X a;
    a.get_ready ();
    unsigned timer = GetTickCount () + 30 * 1000;
    while (timer > GetTickCount ());
}

X::X (): Timer (2, 0), tick (0), ms_max (-1.0), out (0), count (0)
{
    tick = exec_rdtsc ();
}

X::~X ()
{
    printf ("%G%%\n", out / count * 100.0); // Процент «непопаданий»
}

void X::activate ()
{
    __int64 tick2 = exec_rdtsc ();
    __int64 delta = tick2 - tick;
    tick = tick2;
    double ms = double (delta) / timer_scale;
    if (ms > delay)
    {
        printf ("%G\n", ms);
        ms_max = ms;
        ++out;
    }
    ++count;
}

«Нашлепка» для таймера:
Код
// timer.hpp
#pragma once

#include <tchar.h>
#include <windows.h>
#include <mmsystem.h>

void init_timer ();
__int64 exec_rdtsc ();

extern __int64 timer_scale;

class Timer
{
    friend void CALLBACK timer_callback (UINT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR);
public:
    Timer (unsigned delay, unsigned accuracy): handle (NULL), delay (delay), accuracy (accuracy) { }

    virtual bool get_ready ();
    virtual void complete ();

    virtual ~Timer () { complete (); }

protected:
    Timer (const Timer&);
    Timer& operator = (const Timer&);

    virtual void activate () = 0;

    MMRESULT handle;
    unsigned delay, accuracy;
};

Реализация «нашлепки» для таймера:
Код
// timer.cpp
#include <timer.hpp>

const int TIMER_TEST_TIME = 1000; // msec
__int64 timer_scale;

__int64 exec_rdtsc ()
{
    static __int64 result;
    _asm
    {
        rdtsc    // ReaD from Time Stamp Counter
        mov    ebx, offset result
        mov    dword ptr [ebx], eax
        mov    dword ptr [ebx + 4], edx
    }
    return result;
}

void init_timer ()
{
    __int64 start_timer, stop_timer;
    HANDLE current_process = GetCurrentProcess ();
    DWORD common_priority = GetPriorityClass (current_process);
    SetPriorityClass (current_process, REALTIME_PRIORITY_CLASS);
    DWORD tick_count = GetTickCount (), timer = tick_count + TIMER_TEST_TIME;
    start_timer = exec_rdtsc ();
    while (timer > GetTickCount ());
    stop_timer = exec_rdtsc ();
    SetPriorityClass (current_process, common_priority);
    timer_scale = (stop_timer - start_timer) / TIMER_TEST_TIME;
}

void CALLBACK timer_callback (UINT uTimerID, UINT uMsg, DWORD_PTR thread_ptr, DWORD_PTR dw1, DWORD_PTR dw2)
{
    Timer& timer = *cast <Timer*>(thread_ptr);
    timer.activate ();
}

bool Timer::get_ready ()
{
    timeBeginPeriod (accuracy);
    handle = timeSetEvent (delay, accuracy, timer_callback, cast <DWORD_PTR>(this), TIME_PERIODIC);
    return handle != NULL;
}
void Timer::complete ()
{
    if (handle != NULL)
    {
        timeKillEvent (handle);
        handle = NULL;
        timeEndPeriod (accuracy);
    }
}

timer > x из командной строки пишет у меня в x следующее:
Цитата
15.8527
2.96936
2.97209
2.96961
2.96853
2.97072
2.96829
2.96918
2.96884
2.96854
2.96822
2.96965
2.9632
2.96945
2.9695
2.9695
2.96833
2.96683
2.96956

...

2.96898
2.97007
2.96409
2.9694
2.96743
2.27022
2.68064
2.01943
2.96736
2.96892
0%

А потом, при желании, это можно запихать в фак.   

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