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


Автор: ApolloKiD 14.3.2013, 12:37
Доброго времени суток.

После долгого поиска в интернете, пришёл сюда за помощью.

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

Пример:
Код

BOOL Proc1()
{
    // ---- Здесь нужно остановить время до проверки
    if(DataReceived == 1)
        return TRUE;

    return FALSE;
}

void Proc2()
{
    // ---- А это функция принятия данных, где после установки DataReceived = 1; надо разморозить время в Proc1() чтобы она продолжила работу.
}


Пробовал с критическими секциями, но что-то не получается.

Буду благодарен любым советам.

Заранее спасибо.

Автор: xvr 14.3.2013, 13:37
Цитата(ApolloKiD @  14.3.2013,  12:37 Найти цитируемый пост)
Дело в том что, есть функция, в которой нужно остановить время, по началу пробовал циклом, но цикл останавливает время во всём процессе, тем самым другие функции не могут выполнить свою работу, пока цикл не закончится.

Разумеется. И любые другие способы так же заморозят все, пока не кончится функция.

Вам нужен параллельно выполняющийся поток - его можно приостановить, при этом функции в другом потоке будут выполняться.

См. http://msdn.microsoft.com/en-us/library/ms682453%28VS.85%29.aspx (а лучше http://msdn.microsoft.com/en-us/library/kdzttdcb.aspx), http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396%28v=vs.85%29.aspxи http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032%28v=vs.85%29.aspx

Автор: ApolloKiD 14.3.2013, 14:02
Благодарю за ответ.

А есть способ без потоков?

Например как с критическими секциями: 
Код

void Proc0()
{
    EnterCriticalSection(&m_CR); // ---- Первый вход в секцию
    // ---- 
    if(Proc1())
    {
        LeaveCriticalSection(&m_CR);  // ----  Второй выход из секции
    }
}
BOOL Proc1()
{
    EnterCriticalSection(&m_CR); // ---- Второй вход
    // ---- Сюда мы не попадем пока Proc2() не выйдет из секции.
    if(DataReceived == 1)
    {    
        return TRUE;
    }
    return FALSE;
}
void Proc2()
{
    // ---- А это функция принятия данных, где после установки DataReceived = 1; надо разморозить время в Proc1() чтобы она продолжила работу.
    LeaveCriticalSection(&m_CR); // ----  Первый выход из секции
}


Но к сожалению, этот способ не работает, критическую секцию он обходит всё равно и идет дальше, не смотря на то, что он должен остановится.

Или я не так понял работу критических секций.

Автор: feodorv 14.3.2013, 14:37
Цитата(ApolloKiD @  14.3.2013,  15:02 Найти цитируемый пост)
А есть способ без потоков?

Цитата(ApolloKiD @  14.3.2013,  15:02 Найти цитируемый пост)
этот способ не работает

А зачем критические секции без потоков?

Не ясна структура Вашей программы. Она однопоточная, и если вы приостановите выполнение этого потока в какой-то функции, то, естественно, приостановится весь поток.
Но Вам этого не надо, а надо что-то другое. Что делают другие функции в те моменты, когда Вам хочется приостановить время? Как вообще вызывается proc2, которая должна "пробуждать" приостановленную Proc0?

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

Автор: ApolloKiD 14.3.2013, 15:34
Proc2() вызывается при принятии данных.

Вот как всё выглядит на самом деле:
Код

void Proc0()
{
    // ---- Здесь отправляются данные для обработки

    /* Здесь надо заморозить функцию сразу после отправки данных, для ожидания ответа. */
    if(Proc1())
    {
        // ... тут действие
    }
}
BOOL Proc1()
{
    // ---- Сюда мы не попадем пока Proc2() не приймет данные.
    if(Proc2() == 1) // Дело в том что данные могут не прийти сразу, а с какой-то паузой, и возвращаемое значение будет не той что надо. 
    {    
        return TRUE;
    }
    return FALSE;
}
int Proc2() //Функция вызывается когда данные приходят
{
    // ---- Данные пришли, теперь можно разморозить функцию Proc0().
    return DataReceived;
}

Автор: baldina 14.3.2013, 16:42
ApolloKiD, раз это асинхронный ввод/вывод, одной функцией не выйдет.
при асинхронной обработке одна чать программы посылает запрос и устанавливает обработчик (функцию), срабатывающую на прием данных.
придется разбить код Proc0 на две части: отправка данных и получение данных. 
как именно это делать зависит от того, чем (какой библиотекой/функциями) вы пользуетесь для отправки/получения

Добавлено через 2 минуты и 45 секунд
если не вдаваться в подробности, ваш код должен быть переписан примерно так:
Код

void Proc0()
{
    // ---- Здесь отправляются данные для обработки
}
/*
BOOL Proc1()
{
    // ---- Сюда мы не попадем пока Proc2() не приймет данные.
    if(Proc2() == 1) // Дело в том что данные могут не прийти сразу, а с какой-то паузой, и возвращаемое значение будет не той что надо. 
    {    
        return TRUE;
    }
    return FALSE;
}
*/
void Proc2() //Функция вызывается когда данные приходят
{
    // ---- Данные пришли, теперь можно разморозить функцию Proc0().
    {
        // ... тут действие
    }
}


Автор: volatile 14.3.2013, 18:17
ApolloKiD, я так понял у вас приложение однопоточное.
Не ясно только куда/от куда вы посылаете/прнимаете данные.
Другому приложению, чтоли? (походу, если по сети, то тоже значит что другому приложению)

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

Автор: k0rvin 14.3.2013, 19:04
Ниче не понял. Наверное так, например:
Код

void Proc0()
{
    SendData(data);
    int response = RecieveResponse();
    Proc1();
    if (response == 1)
    {
        // ... тут действие
    }
}

void Proc1()
{
    // ---- Сюда мы не попадем пока Proc2() не приймет данные.
}

Автор: ApolloKiD 14.3.2013, 22:19
baldina, WinSock.
volatile, Да, вы правильно поняли, другому приложению.
k0rvin, Так не пробовал, потому что данные сначала попадают на протокол и там идет функция принятия данных.

Пример:

Код

void Protocol(BYTE HeadCode, unsigned char * aRecv, int aLen)
{
    switch (HeadCode)
    {
    case 0x00:
        {
            // ---- Здесь Proc2() принимает данные
        }
        break;
    }
}

Автор: volatile 14.3.2013, 23:50
ApolloKiD, не вникая глубого, скажу имхо, 
Проще всего вам в данном случае сделать второй поток, и всю функцию ожидания ответа запустить в нем.

Если не хотите ни в какую другой поток, придецца переделывать приложение конкретно.
Потому что у вас все не так. Нужен цикл обработки сообщений (или что-то в этом роде),
нужны быстрые обработчики этих сообщений, т.е. отдельные функции: послал, принял, обработал, и т.д.
Никакая из них ничего не должна ждать. 
Тот обработчик, которого у вас ждут, при завершении просто посылает сообщение,
это сообщение обабатываецца, то есть по факту готовности, а не ожидая у моря погоды.





Автор: baldina 15.3.2013, 17:19
ApolloKiD, 

установление соединения со стороны сервера выглядит так:
1. подготовка соединения, начало прослушивания
create socket(protocol) -> bind (port) -> listen()
2. установка соединения (инициированного клиентом)
accept()
в этот момент сервер начинает обслуживает данное соединение. что бы дать ему возможность отвечать и на другие запросы, нужно либо мультиплексировать обслуживание (асинхронный ввод/вывод), либо (проще, но накладнее) создать отдельный поток для данного соединения.
3. send()/recive() для данного соединения

со стороны клиента чуть иначе, но похоже
1. подготовка соединения
create socket(protocol)
2. установка (инициация) соединения
сonnect()
в этот момент клиент готов читать и писать. если параллельно с обменом данными нужно делать другую работу (например, данные приходят время от времени, и нужно их отображать по мере поступления, "в фоне"), recive() нужно делать либо в отдельном потоке, либо асинхронно.
3. send()/recive() для данного соединения

для асинхронного обмена можно использовать 
1. pool() или select(), которые могут проверить состояние сокета(ов) без блокировки (через таймаут)
2. неблокирующий режим. для перевода в этот режим используется ioctlsocket(). теперь recv() будет не блокировать поток, а возвращать управление сразу (с ошибкой, если данные еще не пришли)
3. WSAAsyncSelect - вариант неблокирующего select() для оконных приложений, факт готовности приема/отправки данных передается через очередь сообщений windows

Автор: feodorv 15.3.2013, 21:39
Цитата(baldina @  15.3.2013,  18:19 Найти цитируемый пост)
WSAAsyncSelect - вариант неблокирующего select() для оконных приложений

Или WSAEventSelect/WSAWaitForMultipleEvents для не оконных)))

Автор: baldina 15.3.2013, 22:41
виноват. WSAAsyncSelect

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