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

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

main(){

// do some stuff....

    while(1) {
        int newFD =
            accept(sockFD, (struct sockaddr *)&client_addr, &client_addr_size);
        if(newFD == -1) {
            std::cerr << "Error while Accepting on socket" << std::endl;
            continue;
        }

        if(!fork()) {

            close(sockFD); // close child sockfd - not needed here

            // lalala do stuff send message here                

            close(newFD);  // finally close its newFD - message sent, no use 
            return 0;
        }
        close(newFD);  // close parent newFD - no use here
    }

    // now execution never reaches here
    close(sockFD);      // so how to handle this?
    freeaddrinfo(res);  // and this?

    return 0;
}

Ответ 1

Вы можете и, вероятно, должны добавить обработчик вывода, если ваш код будет использоваться другими людьми, или вы сами просто хотите его очистить. В вашем обработчике вы можете переключить флаг, который завершает цикл while(). Следующий код будет работать на 100% штрафом для этого варианта использования и является надежным и кросс-платформенным, но если вы хотите делать более сложные вещи, вы должны использовать надлежащие поточные операционные функции, определенные ОС, или что-то вроде Boost или С++ 11

Сначала объявите две глобальные переменные, сделайте их volatile, чтобы компилятор всегда заставлял нас читать или записывать его фактическое значение памяти. Если вы не объявите его volatile, тогда возможно, что компилятор может поместить его значение в регистр, который сделает это неработоспособным. С помощью volatile set он будет считывать местоположение памяти в каждом цикле и работать правильно, даже с несколькими потоками.

volatile bool bRunning=true;
volatile bool bFinished=false;

и вместо вашего цикла while(1) {} измените его на

while(bRunning)
{
    dostuff
}
bFinished=true;

В вашем обработчике вы просто установите bRunning=false;

void ExitHandler()
{
    bRunning=false;
    while(bFinished==false) { Sleep(1); }
}

Вы не указали операционную систему, но похоже, что вы основаны на Linux, для установки обработчика на Linux вам это нужно.

void ExitHandler(int s)
{
    bRunning=false;
}

int main()
{
    struct sigaction sigIntHandler;
    sigIntHandler.sa_handler = ExitHandler;
    sigemptyset(&sigIntHandler.sa_mask);
    sigIntHandler.sa_flags = 0;
    sigaction(SIGINT, &sigIntHandler, NULL);
    while(bRunning)
    {
        dostuff
    }
    ...error_handling...
}

И в Windows, когда вы являетесь консольным приложением, это следующее.

BOOL WINAPI ConsoleHandler(DWORD CEvent)
{
    switch (CEvent)
    {
        case CTRL_C_EVENT:
        case CTRL_BREAK_EVENT:
        case CTRL_CLOSE_EVENT:
        case CTRL_LOGOFF_EVENT:
        case CTRL_SHUTDOWN_EVENT:
            bRunning = false;
            while (bFinished == false) Sleep(1);
            break;
    }
    return TRUE;
}

int main()
{
    SetConsoleCtrlHandler(ConsoleHandler, TRUE);
    while(bRunning()
    {
        dostuff
    }
    ...error_handling...
}

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

Еще одна вещь, которую стоит отметить: по умолчанию Windows только дает вам ~ 5 секунд, чтобы закрыть ее, прежде чем она вас прекратит. Это во многих случаях является неудачным, и если требуется больше времени, вам нужно будет изменить настройку реестра (плохая идея) или реализовать службу, которая имеет лучшие возможности для таких вещей. Для вашего простого случая это будет хорошо.

Ответ 2

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

Теперь, что касается имеющихся ресурсов, нет причин не рассматривать их, как все ресурсы на С++. Принятое правило заключается в привязке их к объекту, который выдает их в свой деструктор, см. Также идиому RAII. Таким образом, даже если на каком-то более позднем этапе кто-то добавил оператор break, код все равно будет вести себя корректно.

BTW: Более серьезная проблема, которую я вижу здесь, - отсутствие надлежащей обработки ошибок в целом.