2015-12-03 4 views
0

У меня есть функция, в которой я вызываю _open несколько раз.Когда звонить _pclose?

Если _popen возвращает NULL, мне нужно позвонить _pclose перед тем, как функция вернется?

Я отметил 3 местоположения, где, как мне кажется, должно быть вызвано _pclose.

В каком из этих мест я должен позвонить _pclose?

bool theFunction() 
{ 
    FILE* pPipe; 
    char buffer[1000]; 
    if((pPipe = _popen("dir", "rt")) == NULL) 
    { 
     //location 1 
     _pclose(pPipe); 
     return false; 
    } 

    while(fgets(pipeBuffer, maxBufferSize, pPipe)) 
    { 
     printf(pipeBuffer); 
    } 

    if((pPipe = _popen("cls", "rt")) == NULL) 
    { 
     //location 2 
     _pclose(pPipe); 
     return false; 
    } 

    //location 3 
    _pclose(pPipe); 

    return true; 
} 
+0

Вы не можете закрыть все, что не удалось открыть. Посмотрите на свой первый пример, вы пытаетесь закрыть 'NULL'. –

+0

Подумайте об этом с точки зрения '_pclose()' ... если вы передали его 'NULL', как он мог знать, что закрыть? – FatalError

+0

Хорошо, извините, если это показалось мне плохим. Хотя я понял, что pPipe - это «Null» в этих точках, я новичок в трубах и этих командах. Я спросил, потому что я хотел убедиться, что в '_pclose' ничего не было очищено. Спасибо за быстрый ответ. – user3731622

ответ

1

Простой: закройте трубу, если сможете открыть ее, но больше не нужно. Итак:

bool theFunction() 
{ 
    FILE* pPipe; 
    char buffer[1000]; 
    if((pPipe = _popen("dir", "rt")) == NULL) 
    { 
     return false; 
    } 

    while(fgets(pipeBuffer, maxBufferSize, pPipe)) 
    { 
     printf(pipeBuffer); 
    } 

    // The fact that you have to close it here in the middle of nowhere 
    // should ring a bell that you need to think about separation of concern 
    _pclose(pPipe); 

    if((pPipe = _popen("cls", "rt")) == NULL) 
    { 
     return false; 
    } 

    _pclose(pPipe); 
    return true; 
} 
+0

Почему вы разместили свой первый звонок на '_pclose', где вы сделали? – user3731622

+1

Потому что после этого вы перезаписываете 'pPipe', поэтому вы теряете значение первого канала, и вы больше не можете его закрывать. –

1

Если вы успешно создать трубу с popen, но не называют pclose, то память, занимаемая объектом FILE не освобождается. Хуже того, есть внешне видимые последствия. Детский процесс, который был создан popen, может задерживаться. Когда вы popen, процесс создается с помощью fork. Соответствующий waitpid может не произойти до тех пор, пока не вызывается pclose. (Я считаю, что это типичная, очевидная реализация, и именно так я реализовал всплывающие функции для других языков программирования.)

Хотя Win32 не имеет fork и wait, вероятно, аналогичная проблема с ресурсами в библиотеке Microsoft C Library _popen. В дескрипторе трубы FILE, вероятно, есть внутренний дескриптор Win32 для процесса, который не подпадает под действие CloseHandle до тех пор, пока не будет вызван _pclose. Плюс другие ресурсы, такие как каналы Win32, которые общаются с этим процессом. Если вы не закрываете трубку, вы пропустите эти ресурсы.

О передаче нулевой указатель. Это не-no с оригинальной функцией POSIX. Поведение не определено, если pclose вызывается нулевым указателем. POSIX говорит, что «[i] f поток аргументов в pclose() не является указателем на поток, созданный popen(), результат pclose() не определен». (Нулевой указатель не является указателем на поток, даже если он был возвращен popen).

Microsoft разрешает _pclose называть нулевым указателем. Это documented in MSDN, и поведение _pclose возвращает -1 и устанавливает псевдо-переменную errno в EINVAL.

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