2015-06-24 13 views
4

Мне нужен способ приостановить выполнение функции в течение нескольких секунд. Я знаю, что могу использовать метод sleep для этого, но этот метод «замораживает» приложение во время его выполнения. Я также знаю, что я могу использовать что-то вроде кода ниже, чтобы избежать замораживания:Delphi: спящий режим без зависания и процессов

// sleeps for 5 seconds without freezing 
for i := 1 to 5 do 
    begin 
    sleep(1000); 
    application.processmessages; 
    end; 

Есть две проблемы такого подхода: один является тот факт, замораживание до сих пор происходит каждый за одну секунду, а вторая проблема является призвание " application.processmessages "каждую секунду. Мое приложение имеет интенсивность процессора, и каждый вызов процесса вызывает много ненужной работы, которая использует излишнюю мощность ЦП; Я просто хочу приостановить рабочий процесс, не более того.

Что я на самом деле нужно было бы способ приостановить исполнение так же, как в TTimer, в приведенном ниже примере:

// sleeps for 5 seconds 
    mytimer.interval := 5000; 
    mytimer.enabled := true; 
    // wait the timer executes 
    // then continue the flow 
    // running myfunction 
    myfunction; 

Проблема такого подхода является «MyFunction» не будет ждать для MyTimer, он будет запускаться сразу после включения mytimer.

Есть ли другой подход для достижения такой паузы, как я хочу?

Заранее благодарен.

+0

Так мой лучший вариант - использовать много TTimers с паузами, которые я хочу? – delphirules

+0

Я немного озадачен фразой «каждый вызов вызова процесса делает много ненужной работы». Является ли ProcessMessages похожим на то, что делается, когда приложение не замерзает? Поэтому, если _not freezing_ делает _unnecessary work_, это должна быть область для исправления в первую очередь. –

+1

Я делал такие вещи в различных приложениях по разным причинам. Самое главное, что это зависит от того, почему вам нужно его приостановить, - что будет направлять какой метод вы можете использовать для его обработки. – MikeD

ответ

10

Как указывал Дэвид, опция best состоит в том, чтобы переместить работу в отдельную нить и полностью заблокировать основную резьбу. Но если вы должны заблокировать основной поток, то, по крайней мере, вы должны только позвонить по телефону ProcessMessages(), когда на самом деле есть сообщения, ожидающие обработки, и пусть поток сется в остальное время. Вы можете использовать MsgWaitForMultipleObjects() справиться с этим, например:

var 
    Start, Elapsed: DWORD; 

// sleep for 5 seconds without freezing 
Start := GetTickCount; 
Elapsed := 0; 
repeat 
    // (WAIT_OBJECT_0+nCount) is returned when a message is in the queue. 
    // WAIT_TIMEOUT is returned when the timeout elapses. 
    if MsgWaitForMultipleObjects(0, Pointer(nil)^, FALSE, 5000-Elapsed, QS_ALLINPUT) <> WAIT_OBJECT_0 then Break; 
    Application.ProcessMessages; 
    Elapsed := GetTickCount - Start; 
until Elapsed >= 5000; 

В качестве альтернативы:

var 
    Ret: DWORD; 
    WaitTime: TLargeInteger; 
    Timer: THandle; 

// sleep for 5 seconds without freezing 
Timer := CreateWaitableTimer(nil, TRUE, nil); 
WaitTime := -50000000; // 5 seconds 
SetWaitableTimer(Timer, WaitTime, 0, nil, nil, FALSE); 
repeat 
    // (WAIT_OBJECT_0+0) is returned when the timer is signaled. 
    // (WAIT_OBJECT_0+1) is returned when a message is in the queue. 
    Ret := MsgWaitForMultipleObjects(1, Timer, FALSE, INFINITE, QS_ALLINPUT); 
    if Ret <> (WAIT_OBJECT_0+1) then Break; 
    Application.ProcessMessages; 
until False; 
if Ret <> WAIT_OBJECT_0 then 
    CancelWaitableTimer(Timer); 
CloseHandle(Timer); 
+0

Отлично, спасибо! о / – delphirules

8

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

+0

Итак, если у меня есть много задач для приостановки, мне нужен один поток для каждого? Нет способа использовать сон, как я хочу? – delphirules

+2

Вызовите Sleep в потоке пользовательского интерфейса, и вы убьете пользовательский интерфейс. Ergo, не вызывайте Sleep в потоке пользовательского интерфейса. Ergo, если вы хотите вызвать Sleep, сделайте это в другом потоке. Что касается того, как наилучшим образом решить вашу актуальную проблему, мы не можем полностью понять эту проблему. –

+1

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

1

Весьма сомнительно, что Application.ProcessMessages действительно потребляет слишком много процессорного времени. Вы можете попытаться сохранить момент времени, когда вы начинаете ждать, а затем начинаете повторять Application.ProcessMessages до ...; круг, проверяющий временной интервал между сохраненным и текущим временем.

+2

Это занятая петля, которая будет привязывать процессор. Не говоря уже о том, что ProcessMessages являются злыми. –

0

Если вы не имеете проблему с помощью таймера, вы можете сделать это:

(ouside the timer-event:) 
mytimer.interval := 5000; 
mytimer.tag:=0; 
mytimer.enabled := true; 

(inside the timer-event:) 
mytimer.tag:=mytimer.tag+1; 
if mytimer.tag=2 then begin 
    mytimer.enabled:=false; 
    myfunction; 
end; 
Смежные вопросы