Как сделать аналог прерывания?

Anna551

Есть функция, которая возвращает результат через нефиксированное время (0-120 секунд)
Как аккуратно (без рамножения таймеров) можно реализовать "таймаут" для нее? То есть, чтобы не позднее чем через фиксированное время возвращался, быть может пустой, результат?
Если что, язык - Objective C.

Corrector

Использовать объект синхронизации WaitableTimer
Запрограммировать его на переход в сигнальное состояние через заданное время

Werdna

Запрограммировать его на переход в сигнальное состояние через заданное время

А на событие нельзя повесить? Ну типа событие "на сокет пришло что-то", вроде как обычный poll/select есть на всех операционках.

Corrector

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

Anna551

В общем сделал так:
в вызываемой функции запускаю другой поток, где запускаю рабочую функцию.
в основном потоке кручу while, смотрящий, не появилось ли что-либо в буле answerFetched. Если появилось, то функция завершилась и мы берем данные и возвращаем их, если не появилось по истечению времени - килять тот поток и возвращать nil.
Плюс: интерфейс остался в рамках одного метода, без оповещений и сигналов.
Минус: основной поток грузится этим бессмысленным whileом.
Покатит такой подход?

zorin29

Нет. Это активное ожидание, его лучше избегать.

Anna551

Ну да.. В данном случае оно прокатит, но в общем и целом не ня... А если разбить это активное ожидание на несколько пассивных?
В смысле
 while !answer) && (a<FireTIme
{
a=[[NSDate alloc] init].timeIntervalSince1970;
}

Заменить на
 while !answer) && (a<FireTIme
{
sleep (0.1);
a=[[NSDate alloc] init].timeIntervalSince1970;
}

zorin29

Ну это все равно хуже, чем ожидание push-нотификации, но лучше, чем первый вариант.

Corrector

Лучше сделай так:
В основном потоке
InitializeWaitableTimer(hEventTimeout, OPERATION_TIMEOUT) //инициализация таймера
CreateThread //создание дополнительного потока
EventIndex = WaitForMultipleObjects([hEventThreadReady, hEventTimeout)], ....); //Ожидание события, которое наступит раньше
В коде потока
a = CallHeavyFunction(..) //вызов той самой долгой функции
SetEvent(hEventThreadReady, TRUE); //установка объекта в сигнальное состояние
Кстати, в данном простейшем случае можно вообще обойтись функцией WaitForSingleObject и без таймера, т.к. в этой функции есть свой внутренний таймаут

okis

Это всё windows-specific, а у автора obj-c

evgen5555

поищи в доках по слову NSTimer

Anna551

Да... навскидку аналога waitformultiply под iOS я не вижу, хотя о чем-то таком я и мечтал

Andbar

А waitforsingle с таймаутом там тоже отсутствует? А то ведь можно было бы просто подождать завершения потока.

evgen5555

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

rosali

Кстати интересно, а что собираешься делать, если стаймаутилось? Канселить рабочий тред? Я честно говоря objc не знаю совсем, но нагуглил, что вроде как нет возможности принудительно остановить тред, только:
> The correct way to stop your thread executing is to ask it nicely to stop executing.
и
> cancel method only informs the thread that it is cancelled ... It's then the responsibility of the thread itself to check this and exit.

salamander

Да... навскидку аналога waitformultiply под iOS я не вижу, хотя о чем-то таком я и мечтал
select ? Или iOS POSIX-совместимая только на словах?
Ну и да, беглый гуглинг подсказал, что по крайней мере сигналы там имеются. Организуй рабочему треду сигнал в нужный момент, а в обработчике сигнала прибей тред. Не?
ЗЫ: функция alarm (SVr4, POSIX.1-2001, 4.3BSD) как раз нужна для организации таких сигналов, а signal (POSIX.1-2001) для установки обработчика.
ЗЗЫ:
пример на C под обычный Linux, под iOS должно быть аналогично, если сигналы работают так же.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

volatile int x = 0;

void useless_work(void)
{
while (1) {
x++;
}
}

void sighandler(int sig)
{
printf("%d\n", x);
exit(0);
}

int main(void)
{
signal(SIGALRM, sighandler);
alarm(2);
useless_work;
return 0;
}

evgen5555

Причем там вроде и делегаты неплохо поддерживаются, непонятно, зачем треды вообще нужно убивать.

vall

это слишком жёстко. в обработчике сигнала лучше выставить флаг прерывания.

Anna551

Ну вроде есть iOS классический способ:

@protocol workDelegate
-(void) answerFetched: (id) answer;
@end


...
-(void) doWork
{
answer=doReallyWork;
[self performSelectorInMainThread:@selector(Notifier) withObject: nil];
}

-(void) Notifier
{
if (needed) {[self.delegate answerFetched:answer]; needed=0;}
}

-(void) mainFunction: (double) timeout
{
needed=1;
[self performSelectorInBackground:@selector(doWork) withObject:nil];
[self performSelectorInBackground:@selector(Notifier) withObject:nil afterDelay:timeout];
}

В крайнем случае, если есть какие-то существенные ограничения, задается конкретный поток для doWork, который радостно уничтожается по таймауту.
Но мне бы очень хотелось, чтобы ответ возвращался именно вызываемой функцией. Поэтому и приходится прибегать к такому кошмару.
Оставить комментарий
Имя или ник:
Комментарий: