2013-02-20 3 views
2

У меня есть небольшая программа на C++, которая пингорует другие компьютеры в сети и отправляет информацию о статусе через другую сеть. Программа запускается как демон, поэтому процесс запуска выдает дочерние элементы, а затем вызывает exit. Эта программа перекрестно скомпилирована для работы на двух разных архитектурах: x86 и ARM. Версия GCC составляет 4,4 и 3,5 соответственно. Я могу скомпилировать и запустить программу на x86, и она работает безупречно. Однако, когда я запускаю программу на ARM, она зависает в любое время, когда я звоню exit, а не сразу после fork. У меня нет функций, зарегистрированных с atexit или on_exit. Ниже приведены мои включает в себя:exit (3) зависает в Linux C++

#include <cstdio> 
#include <cstdlib> 
#include <cstring> 

#include <iostream> 
#include <sstream> 
#include <string> 
#include <set> 
#include <vector> 

#include <boost/bind.hpp> 
#include <boost/asio.hpp> 
#include <boost/thread.hpp> 
#include "telnet_client.h" 

#include <stdint.h> 

#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/select.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <sys/time.h> 
#include <netdb.h> 
#include <net/if.h> 
#include <sys/ioctl.h> 
#include <unistd.h> 
#include <syslog.h> 
#include <customlib1.h> 
#include <customlib2.h> 

Ниже приведены мои НКУ команды:

arm-none-linux-gnueabi-g++ -Wall -DBUILDSTAMP="\"`date '+%F %T'`\"" -g -ggdb -O0 -I/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/include -DEMBEST_ARM -I/usr/local/share/arm/boost/src -I../include/ -I../include_rms -c can_wifid.cpp -o can_wifid.o 
arm-none-linux-gnueabi-g++ -Wall -DBUILDSTAMP="\"`date '+%F %T'`\"" -g -ggdb -O0 -I/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/include -DEMBEST_ARM -I/usr/local/share/arm/boost/src -I../include/ -I../include_rms -c telnet_client.cpp -o telnet_client.o 
arm-none-linux-gnueabi-g++ -Wall -DBUILDSTAMP="\"`date '+%F %T'`\"" -g -ggdb -O0 -I/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/include -DEMBEST_ARM -I/usr/local/share/arm/boost/src can_wifid.o telnet_client.o -L/usr/local/arm/arm-2007q1/arm-none-linux-gnueabi/libc/usr/lib -L../lib_embest_arm -L../lib_rms_embest_arm -Wl,-Bdynamic -lutilities -lboost_system -lboost_thread -lcanprovider -lembestcan -o can_wifid 

Даже просто разборе мои параметры командной строки с getopt затем вызвать exit после сообщения версия вызывает эта проблема (простейший случай моя программа). Кто-нибудь когда-либо испытывал что-то подобное, когда exit просто зависает?

EDIT: Добавлен код для первой части главной функции:

struct canwifid_options 
{ 
public: 
bool daemon_mode; 
int verbosity; 

canwifid_options() 
{ 
    this->daemon_mode = false; 
    this->verbosity = LOG_NOTICE; 
} 
}; 

static canwifid_options options; 

int main(int argc, char * argv[]) 
{ 
int LoggingOptions = LOG_CONS|LOG_NDELAY|LOG_PID; 
pid_t Pid; 

ParseCommandLine(argc, argv); 

if (!options.daemon_mode) 
{ 
    LoggingOptions |= LOG_PERROR; 
} 

openlog("can_wifid", LoggingOptions, LOG_USER); 

setlogmask(LOG_UPTO(options.verbosity)); 

if (options.daemon_mode) 
{ 
    Pid = fork(); 

    if (Pid < 0) 
    { 
     // couldn't fork off and create a child process 
     // log it, %m is a special syslog flag 
     syslog(LOG_CRIT, "Unable to create daemon [Error: %m]"); 
     exit(ESRCH); 
    } 
    else if (Pid > 0) 
    { 
     // we're the parent, so we're done and out of here 
     exit(EXIT_SUCCESS); 
    } 
    else 
    { 
     // we're the child, take control of the session. 
     setsid(); 

     // change to the root directory so we don't retain unnecessary control 
     // of any mounted volumes 
     chdir("/"); 

     // clear our file mode creation mask 
     umask(0000); 
    } 
} 
else 
{ 
    // get our process ID 
    Pid = getpid(); 
} 

syslog(LOG_INFO, "Running as %s", options.daemon_mode ? "daemon" : "standalone"); 

    // Network code here, snipped for clarity 
} 

И ParseCommandLine функция:

static void ParseCommandLine(int argc, char *argv[]) 
{ 
int c; 

while ((c = getopt(argc, argv, "dhqvDV?")) > 0) 
{ 
    switch (c) 
    { 
     case 'd': 
      options.daemon_mode = true; 
      break; 
     case 'V': 
      VersionMessage(argv); 
      exit(EXIT_SUCCESS); 
      break; 
     case 'q': 
      options.verbosity = LOG_WARNING; 
      break; 
     case 'v': 
      options.verbosity = LOG_INFO; 
      break; 
     case 'D': 
      options.verbosity = LOG_DEBUG; 
      break; 
     case 'h': 
     case '?': 
     default: 
      HelpMessage(argv); 
      exit(EXIT_SUCCESS); 
      break; 
    } 
} 

return; //done 
} 
+0

Давайте посмотрим код из fork(), чтобы выйти(). – wallyk

+2

Вы уже пробовали «Hello, World», скрем-скомпилированный? Сбой программы, если вы только что вернулись из основного? Если вы можете сделать версию без сбоев, разверните ее по строкам, чтобы создать самую простую сбойную версию. – hyde

+0

Обратите внимание, что среда выполнения обычно добавляет обработчики atexit, например. закрыть FILE * или запустить деструкторы глобальных объектов C++. Это может обеспечить понимание, если вы сможете захватить вывод 'strace', когда процесс зависает, или подключить отладчик и создать обратную трассировку. Другое дело отметить, что многопоточные программы forking() очень опасны, так как они несут большой потенциал для условий гонки в замках (а не только ваши собственные, но внутренние мьютексы, используемые malloc, FILE * и т. Д.) - это зависит от когда вилка выполнена. – nos

ответ

0

Проблема я столкнулся один раз в том, что называя exit попытки выйти и вызовы глобальных деструкторов БЕЗ попыток разматывать стек или вызвать любые деструкторы для локальных объектов в стеке. Это может легко проявиться, если у вас есть какие-либо блокировки, которые могут потребоваться для глобальных деструкторов. Например, эта программа ТУПИКИ в выходе (на самом деле в глобальном dtor):

#include <iostream> 
#include <mutex> 

std::mutex lock; 

class A { 
public: 
    A() { 
     std::lock_guard<std::mutex> acquire(lock); 
     std::cout << "ctor A" << std::endl; 
    } 
    ~A() { 
     std::lock_guard<std::mutex> acquire(lock); 
     std::cout << "dtor A" << std::endl; 
    } 
}; 

A a; 

int main() 
{ 
    std::lock_guard<std::mutex> acquire(lock); 
    exit(0); 
} 

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

Если вы хотите выйти, если вы правильно раскручиваете стек (что требуется для структурированного кода RAII), вы не можете вызвать exit. Вместо этого вам нужно выбросить исключение, которое поймано (только) в главном и приведет к возврату main.

+0

В настоящее время я не использую никаких замков, но я буду помнить о вашем решении. Большое спасибо за ваше предложение Криса. –

+0

@AlexMarshall: вещи, отличные от блокировок, могут проявляться таким же образом - ключевая проблема заключается в том, что объекты в стеке не уничтожаются должным образом, когда вы вызываете «exit», что приводит к проблемам в глобальных деструкторах. Если вы можете более точно определить, где он висит (а не просто «после вызова exit»), вы можете выяснить, где проблема. –

+0

Спасибо, Крис. Я получил основную идею, но я пытался сказать, что я могу воспроизвести проблему только с printf и выходом. Похоже, что просто включить hpp-файл достаточно, чтобы вызвать проблему. –

Смежные вопросы