Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 20.12.2011, 15:53   #1
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию Перехватчик потоков ввода-вывода

Материал для меня новый и не знакомый. Мне просто нужно понять саму идею.

Если вкратце, нужно сделать что то вроде вот этого:

Код:
while(пока приказа завершится не было)
{ 
     while (пока в трубе что-то есть)
     {
          читаем из трубы;
     }
}

Есть два потока: основной и дочерний. Основной поток отправляет в анонимный канал данные.
Дочерний их читает c помощью: ReadFile(hReadPipeOut, localBuff, MAX_LEN_BUFF, &bytWrt, NULL);
Он будит висеть на этой трубе до бесконечности, пока что нибудь из неё не выудет.

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

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

Как правильно разруливаются подобные ситуации?

Мне нужен сам алгоритм. Сама идея!

Дочерний поток получает данные не целиком, а порциями.
Причем заранее не известно какого размера. Допустим последовательность: "1234567890", он может получить так:
"12345" а потом "67890"
А может всю целиком, или кусками других размеров.

Если дочерний поток пытается читать кусок "12345", а основной поток уже сделал ему флаг окончания работы, то дочерний прекратит работу, так и не прочитав "67890"

То есть, основной поток должен сначала дождаться, пока дочерний не перестанет читать.

А как дочерний поток узнает, все ли он уже прочитал, или ещё нет?

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

Наверняка же есть способ попроще и элегантнее?

Больше всего напрягает то, что дочерний поток весит на трубе до бесконечности, пока туда что нибудь не придёт. Можно сделать так, что бы он не висел на трубе? Если данных в трубе нет - двигался дальше?

Последний раз редактировалось _Bers; 20.12.2011 в 16:04.
_Bers вне форума Ответить с цитированием
Старый 20.12.2011, 21:41   #2
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

ПОБЕДАААА!!!!!!

Труба была упёртой, но я не сдавался! ))

Если кому интересно:

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

И есть отправитель (главный поток. Он тоже не знает, сколько данных будит отправлено читателю, но он хотя бы знает, когда уже нужно закругляться)

Отправитель в диструкторе должен завершить работу читателя. Он активирует сигнал, что пора закруглятся.

Читатель в бесконечном цикле смотрит: труба пустая, или нет? Если труба с данными - читает данные, и дальше крутится в бесконечном цикле
Если же труба пустая - то он смотрит, не загорелся ли фонарик от главного, и не пора ли всем по домам.

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

Поэтому, прежде чем суваться в трубу, он должен убедится что данные в ней есть (иначе залипнет).


Вот и получается:

Вот так главный завершит работу дочернего:
Код:
BersInterceptor::~BersInterceptor()
{
    SetEvent(closeThreadRead);             //просигналим дочернему потоку закрыться
    WaitForSingleObject(hTRead, INFINITE); //ждем, пока дочерний поток не доделает 
    ...                                                     //свою работу

}
А вот так трудится читатель:

Код:
void BersInterceptor::ReadInterceptData()
{
    char localBuff[1024]={0}; DWORD bytesRead=0;
    while(1)
    {
        if( Kolbytes()!=0 )                   //чтение данных происходит только если в файле что-то есть
        {
            ReadFile(hReadPipeOut, localBuff, LEN_DATA, &bytesRead, NULL);
            Buff.assign(localBuff, localBuff+bytesRead);  ViewText(Buff);  
        }
        else
        {
            if( WaitForSingleObject(closeThreadRead,0)==WAIT_OBJECT_0 ) { break; }
        }
    }
    return;
}
Здесь есть не очевидный, но архи важный нюанс:
Проверка сигнала от главного выполняется в блоке else
Блок "иначе" гарантирует, что прежде чем читатель завершит работу, он сначала посмотрит, не пустая ли труба. Что он завершит свою работу не раньше, чем прочитает все данные.

Если этого не сделать - через раз будут случае, когда ещё не все данные были прочитаны.
_Bers вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
C++, переопределение ввода-вывода Erisu Помощь студентам 9 16.06.2011 16:27
Операторы ввода и вывода wsws123 Паскаль, Turbo Pascal, PascalABC.NET 2 04.01.2011 18:12
переопределение ввода и вывода в С++ blackbanny Помощь студентам 12 03.05.2010 13:08
Перенаправление ввода/вывода dudeboy Win Api 0 16.11.2009 11:36
система ввода вывода StudentPolitech Общие вопросы C/C++ 3 02.04.2009 22:22