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


Автор: BlHol 29.4.2006, 10:23
День добрый!

Есть обработчик:

Код

void __fastcall TForm1::Button2Click(TObject *Sender)
{
 long int i;
 long int k;
  for(i=0;i<=1000000000;i++);
  Label1->Font->Color = clGreen;
  i=0;


  for(k=0;k<=100000000;k++);
    Form1->Label2->Font->Color = clBlue;
  }


Так вот. После нажатия на кнопку хочу увидеть, как текст на метке после первой паузы окрашивается сначала в зеленый, а потом после второй паузы в синий. 
А в результате, окрашивание текста происходит сразу в синий. Т.е. такое впечатление, что первая пауза не срабатывает. 

Поэтому вопроса 2:
1. Почему так происходит?
2. Как решить проблему? 


Заранее благодарен.
С уважением. 

Автор: BreakPointMAN 29.4.2006, 12:13
и да поможет тебе
Код
Application->ProcessMessages();

перед вторым циклом (кстати, у него в 10 раз меньше итераций, чем у первого - это так задумано?), а вообще говоря, для таких дел лучше использовать компонент TTimer (вкладка System палитры компонентов C++ Builder) 

Автор: BlHol 29.4.2006, 12:37
Я количество итераций и уменьшал и увеличивал. Те же яйца... 

Автор: Hose 2.5.2006, 09:16
Возможно умный компилятор просто переделывает строку 
Код

  for(i=0;i<=1000000000;i++);
 в 
Код

i = 1000000000;
 которая выполняется намного быстрее и приводит абсолютно к такому же результату. 

Автор: BlHol 2.5.2006, 09:45
Цитата(Hose @ 2.5.2006,  09:16)
Возможно умный компилятор просто переделывает строку 
Код

  for(i=0;i<=1000000000;i++);
 в 
Код

i = 1000000000;
 которая выполняется намного быстрее и приводит абсолютно к такому же результату.

И как с этим бороться? 

Автор: adonin 2.5.2006, 09:54
Цитата(Hose @  2.5.2006,  09:16 Найти цитируемый пост)
 которая выполняется намного быстрее и приводит абсолютно к такому же результату

Ни один компилятор не будет делать такого глубокого анализа кода, чтобы заменять или убирать писанные конструкции. Тем более, что это может нарушить логику программы, программа будет делать не то, что хотел от неё кодер (или не так).
Цитата(BlHol @  29.4.2006,  10:23 Найти цитируемый пост)
Так вот. После нажатия на кнопку хочу увидеть, как текст на метке после первой паузы окрашивается сначала в зеленый, а потом после второй паузы в синий. 
А в результате, окрашивание текста происходит сразу в синий. Т.е. такое впечатление, что первая пауза не срабатывает. 

В таком случае не срабатывает вторая пауза (Нет задержки между окрашиваниями). Увеличте её.
Такой способ задержки - очень не правильно!!!!!!! 
Через год выйдут процессоры, которые будут выполнять твои циклы так быстро, что ты не увидишь задержки вообще.
Используй таймеры. 

Автор: Hose 2.5.2006, 10:30
Цитата(adonin @  2.5.2006,  09:54 Найти цитируемый пост)
Ни один компилятор не будет делать такого глубокого анализа кода, чтобы заменять или убирать писанные конструкции. Тем более, что это может нарушить логику программы, программа будет делать не то, что хотел от неё кодер (или не так).


открываем VS 2003
создаем консольное приложение
текст программы:

Код

int main()
{
    unsigned long i = 0;
    unsigned long j = 0;
    for (i = 0; i < 1000000000; i++)
        for (j = 0; j < 1000000000; j++);    
    int n = i + j;
    printf("%d", n);
    return 0;
}


Залезаем в свойства проекта и ставим оптимизацию maximum speed
запускаем
По моим скромным и весьма оптимистичным подсчетам данный цикл должен выполняться около 10 лет.
Не проходит и секунды, на экране верный результат.

Добавлено @ 10:38 
Цитата(BlHol @  2.5.2006,  09:45 Найти цитируемый пост)
И как с этим бороться?

я так понимаю, ты пишешь в билдере. Я его в глаза не видел но подозреваю, что в нем месть свойства проекта и наверняка можно отключить оптимизацию. 
в VS 2003 это делается так:
меню Project-> Properties->C/C++->optimisation->optimisation->disable
но
Цитата(adonin @  2.5.2006,  09:54 Найти цитируемый пост)
Такой способ задержки - очень не правильно!!!!!!!
...
Используй таймеры. 

 

Автор: BlHol 2.5.2006, 11:09
Цитата(Hose @  2.5.2006,  09:16 Найти цитируемый пост)
 В таком случае не срабатывает вторая пауза (Нет задержки между окрашиваниями). Увеличте её.
Такой способ задержки - очень не правильно!!!!!!! 
Через год выйдут процессоры, которые будут выполнять твои циклы так быстро, что ты не увидишь задержки вообще.
Используй таймеры.

Тогда вопрос: почему срабатывает первая пауза и не срабатывает вторая при одинаковых строках кода?

Я уже пробовал увеличивать счетчик во втором цикле, результат тот же.

Я понимаю, что "очень неправильно". Даже с таймером ужо разобрался, а это так, задачка в свободное время. Интерес, чисто, спортивный.

Заранее благодарен.
С уважением. 

Автор: Hose 2.5.2006, 11:13
Кстати у тебя в коде в зеленый цвет окрашивается Label1, а в синий Label2. А из текста создалост впечатление, что ты хочешь один и тотже текст раскрашивать. Возиожно в этом ошибка
 

Автор: adonin 2.5.2006, 11:17
Цитата(Hose @  2.5.2006,  10:30 Найти цитируемый пост)
По моим скромным и весьма оптимистичным подсчетам данный цикл должен выполняться около 10 лет.
Не проходит и секунды, на экране верный результат

Очень интересно, Откомпилял Ваш код с опцией "Assembly with source code". Компилятор VC++ 6.0.
Ни какой оптимизации нету:
Код

_main    PROC NEAR

; 7    : {

    push    ebp
    mov    ebp, esp
    sub    esp, 12                    ; 0000000cH

; 8    :     unsigned long i = 0;

    mov    DWORD PTR _i$[ebp], 0

; 9    :     unsigned long j = 0;

    mov    DWORD PTR _j$[ebp], 0

; 10   :     //for (i = 0; i < 1000000000; i++)
; 11   :         for (j = 0; j < 1000000000; j++);    

    mov    DWORD PTR _j$[ebp], 0
    jmp    SHORT $L530
$L531:
    mov    eax, DWORD PTR _j$[ebp]
    add    eax, 1
    mov    DWORD PTR _j$[ebp], eax
$L530:
    cmp    DWORD PTR _j$[ebp], 1000000000        ; 3b9aca00H
    jae    SHORT $L532
    jmp    SHORT $L531
$L532:

; 12   :     int n = i + j;

    mov    ecx, DWORD PTR _i$[ebp]
    add    ecx, DWORD PTR _j$[ebp]
    mov    DWORD PTR _n$[ebp], ecx

; 13   :     printf("%d", n);

    mov    edx, DWORD PTR _n$[ebp]
    push    edx
    push    OFFSET FLAT:$SG534
    call    _printf
    add    esp, 8

; 14   :     return 0;

    xor    eax, eax

; 15   : }

    mov    esp, ebp
    pop    ebp
    ret    0
_main    ENDP
_TEXT    ENDS
END

Смотрите прыжки на метки $L531: и $L532: - это и есть цикл.

Добавлено @ 11:24 
Hose, Вы правы! VS 2003 в релизе заменил пустой цикл на i=1000000000!!!
BlHol, чтобы этого избежать, отключите оптимизацию в компиляторе, или делайте так:
Код

int main()
{
    unsigned long i = 0;
    unsigned long j = 0;
    for (i = 0; i < 1000000000; i++)
        for (j = 0; j < 1000000000; j++) _asm{nop};    
    int n = i + j;
    printf("%d", n);
    return 0;
}

nop - пустая команда, просто такты процессора кушает. И цикл не пустой, поэтому не оптимизируется.

Добавлено @ 11:32 
Hose, тебе плюс, я бы не додумался до тако объяснения. 

Автор: BlHol 2.5.2006, 11:35
Цитата(Hose @ 2.5.2006,  11:13)
Кстати у тебя в коде в зеленый цвет окрашивается Label1, а в синий Label2. А из текста создалост впечатление, что ты хочешь один и тотже текст раскрашивать. Возиожно в этом ошибка

Сорри! Это я не совсем точно задачу описал. Есть 2 метки. Хочу, чтобы после 1-й паузы одна метка окрашивалась, а после 2-й, вторая (все в одном обработчике). Первая пауза выдерживается (1-я метка окрашивается после 1-го цикла), а вторая нет (т.е. 2-я метка окрашивается тут же). Т.е. складывается ощущение, что два цикла обрабатываются параллельно. Или почти параллельно...  

Автор: cozzzy 2.5.2006, 12:39
BlHol, прочитай предыдущий пост  smile 

И вообще если хочешь паузу используй функцию Sleep 

Автор: armageddon 4.5.2006, 16:09
а почему нельзя, чтобы цикл был не пустой туда забить какаю нибудь не сложныу задачу, например проверка делимости считчика на некоторое число, чтобы результат суммировался.....
на мой взгляд должно сработать 

Автор: adonin 5.5.2006, 12:39
Цитата(armageddon @  4.5.2006,  16:09 Найти цитируемый пост)
а почему нельзя, чтобы цикл был не пустой 

Можно. 

Автор: Coala 5.5.2006, 13:54
Код
void __fastcall TFMain::Button1Click(TObject *Sender) {
  // ждём 2000 миллисекунд после нажатия батона
  Sleep(2000);
  // меняем цвет
  Label1->Font->Color = clGreen;
  // гарантированно меняем
  Application->ProcessMessages();
  // ждём ещё 2000 мс
  Sleep(2000);
  Label2->Font->Color = clBlue;
  Application->ProcessMessages();
}
 
ЗЫ - вместо Sleep можно использовать цикл по GetTickCount, QueryPerformanceCounter или GetProcessTimes (если надо точно замерять интервал времени). У Sleep вообще-то точность - плюс-минус поллаптя. 

Автор: cozzzy 5.5.2006, 14:26
Цитата(Coala @  5.5.2006,  12:54 Найти цитируемый пост)
 У Sleep вообще-то точность - плюс-минус поллаптя. 

Да, но я уверен, что комраду BlHol, не нужна точность до тысяной секунды
А QueryPerformanceCounter тожен не панацея, хоть и самый точный для винды  

Автор: Coala 5.5.2006, 14:34
Цитата(cozzzy @  5.5.2006,  15:26 Найти цитируемый пост)
QueryPerformanceCounter тожен не панацея, хоть и самый точный для винды  
Но не на всех компах работает, проверять надо
Код

LARGE INTEGER a;
if (!QueryPerformanceFrequency(&a)) {
  ShowMessage("Пора поменять компутер");
  return;
}

  

Автор: cozzzy 5.5.2006, 15:28
Цитата(Coala @  5.5.2006,  13:34 Найти цитируемый пост)
Но не на всех компах работает, проверять надо


Угу

Цитата

If the installed hardware supports a high-resolution performance counter, the return value is nonzero.
 

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