Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> поток лочится в open(filename, 0666), pipe, read, open 
:(
    Опции темы
InvalidProperty
Дата 20.11.2007, 13:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 356
Регистрация: 31.10.2007
Где: Россия, Казань

Репутация: 1
Всего: 9



В общем проблема следующего характера:

есть демон, который сразу же после своего создания создает поток, который сразу же отсоединяется - этот поток будет следить за обращением других процессов по пайпу, т.е. будет ждать запрос. Демон работает с сокетами и, когда подключается новый клиент, создается для него отдельный поток, который так же отсоединяется, информация о tid и дескрипторе соединения сохраняется в векторе. Если демон запустить с параметром "-c", то по именованному пайпу передается запрос на вывод всей информации из вектора запущенного демона. Запущенный демон получает эту информацию и по другому именованному пайпу отправляет ответ-строку, содержащую требуемую информацию. Это в идеале... Вся проблема в том, что если демон стартует и тут же запустить процесс с аргументом командной строки "-c", то выводится информация о пустом векторе - что есть логично - но, если сначала законнектить клиента, стартует новый поток, который сразу же ловит segmentation violation, умирает, но дескриптор соединения специально не закрывается и информация об умершем потоке специально не удаляется из вектора, основной поток и поток слежения за пайпом остаются в живых, запускается процесс с параметром "-c" и все...  smile новый процесс и поток слежения в deadlock

Описание работы потока слежения:

Код

int clPipe::openServer()
 {
// <create named pipes>
  if(mkfifo(PIPE_REQUEST_FILE, S_IRUSR | S_IWUSR) == -1)
   if(errno != EEXIST)                // if not exists
    { my_log("can not create named pipe %s - %m", PIPE_REQUEST_FILE); return -1; }

  if(mkfifo(PIPE_RESPONSE_FILE, S_IRUSR | S_IWUSR) == -1)
   if(errno != EEXIST)                // if not exists
    { my_log("can not create named pipe %s - %m", PIPE_RESPONSE_FILE); return -1; }
// </create named pipes>

  if(this->waitRequest() == -1)
   this->die();

  return 0;
 }

int clPipe::waitRequest()
 {
  int        n;
  string    buffer;
  char        recv_line[MAXLINE];

  while(true)
  {
   // <open named pipe>
my_log("here");                         // ЭТО ЕЩЕ ПЕЧАТАЕТСЯ
   if( (this->pipe_request_fd = open(PIPE_REQUEST_FILE, O_RDONLY)) == -1)
    { my_log("can not open named pipe for reading - %s - %m", PIPE_REQUEST_FILE); return -1; }
   // </open named pipe>
my_log("here");                         // А ЭТО УЖЕ НЕТ :(
   while( (n = _read(this->pipe_request_fd, recv_line, MAXLINE)) > 0)
   {
    recv_line[n] = 0;
    try
     { buffer += recv_line; }
    catch(exception)
     { my_log("can not save data into buffer"); return -1; }

    if(strchr(recv_line, CTERM) != NULL)            // wait for term char
     break;
   }
   if(n < 0)
    { my_log("can not read from pipe - %m"); return -1; }

   if(buffer[buffer.length() -1] == CTERM)
    buffer[buffer.length() -1] = 0;

   this->workupPipeAction(buffer.c_str());
   buffer.clear();

   close(this->pipe_request_fd);
   close(this->pipe_response_fd);
  }
 }

void clPipe::die()
 {
  close(this->pipe_response_fd);
  close(this->pipe_request_fd);
  unlink(PIPE_RESPONSE_FILE);
  unlink(PIPE_REQUEST_FILE);
  pthread_exit(NULL);
 }


CTERM - терминатор, введенный искусственно для разделения данных.

Описание работы клиента

Код

int clPipe::openClient(const char *buffer, size_t buffer_size)
 {
  ssize_t    n;

  // <open named pipes>
  if( (this->pipe_request_fd = open(PIPE_REQUEST_FILE, O_WRONLY)) == -1)                         // pipe открывается в любом случае
  {
   my_log("can not open named pipe for writting - %s - %m", PIPE_REQUEST_FILE);
   return -1;
  }
  // </open named pipes>
  _write(this->pipe_request_fd, buffer, buffer_size);
  _write(this->pipe_request_fd, &CTERM, 1);

  n = this->getResponse();

  close(this->pipe_request_fd);
  close(this->pipe_response_fd);

  return n;
 }

int clPipe::getResponse()
 {
  int        n;
  char        recv_line[MAXLINE];
printf("here\n");                                            // ЭТО ПЕЧАТАЕТСЯ
  // <open named pipe>
  if( (this->pipe_response_fd = open(PIPE_RESPONSE_FILE, O_RDONLY)) == -1)
  {
   protei_log(EL_SYSTEM, PR_INFO, "can not open named pipe for reading - %s - %m", PIPE_RESPONSE_FILE);
   close(this->pipe_request_fd);
   return -1;
  }
  // </open named pipe>

  this->response.clear();
printf("here\n");                                                // А ЭТО УЖЕ НЕТ :(
  while( (n = _read(this->pipe_response_fd, recv_line, MAXLINE)) > 0)
  {
   recv_line[n] = 0;
   try
    { this->response += recv_line; }
   catch(exception)
    { sprintf(this->errstr, "can not save data into buffer"); return -1; }

   if(strchr(recv_line, CTERM) != NULL)            // wait for term char
    break;
  }
  if(n < 0)
   { sprintf(this->errstr, "can not read from pipe - %m"); return -1; }

  if(this->response[this->response.length() -1] == CTERM)
   this->response[this->response.length() -1] = 0;

  return 0;
 }


все помечено комментариями. Еще раз повторюсь. Если демон стартовать и сразу же запустить еще один процесс с параметром "-c" - все прекрасно работает, т.е. выводится информация о пустом векторе, если же демон запустить и подконнектить к нему клиента, поток которого сразу же умрет по SIGSEGV, то демон залочится в open() на чтении smile С какого такого перепугу, непонятно, ибо в манах четко написано, что если это пайп, то поток, открывающий его на чтение, будет залочен до тех пор, пока кто-нибудь его не откроет на запись и наоборот. Как видно по каментам, новый процесс (с параметром "-c") открывает пайп на запись, но поток слежения все равно остается залоченным smile 


--------------------
dd if=$0 of=$0 bs=1 count=76 seek=`du -b $0 | awk {'print $1'}` 2>/dev/null
dd if=$0 of=$0 bs=1 count=67 conv=notrunc oflag=append 2>/dev/null
echo $0 >> $0
PM MAIL ICQ Jabber   Вверх
MAKCim
Дата 20.11.2007, 22:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



Цитата(InvalidProperty @  20.11.2007,  13:13 Найти цитируемый пост)
if( (this->pipe_request_fd = open(PIPE_REQUEST_FILE, O_RDONLY)) == -1)
    { my_log("can not open named pipe for reading - %s - %m", PIPE_REQUEST_FILE); return -1; }

какое значение тут имеет errno?
что выдает perror(NULL) перед return -1?


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
InvalidProperty
Дата 21.11.2007, 09:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 356
Регистрация: 31.10.2007
Где: Россия, Казань

Репутация: 1
Всего: 9



Цитата(MAKCim @ 20.11.2007,  22:09)
Цитата(InvalidProperty @  20.11.2007,  13:13 Найти цитируемый пост)
if( (this->pipe_request_fd = open(PIPE_REQUEST_FILE, O_RDONLY)) == -1)
    { my_log("can not open named pipe for reading - %s - %m", PIPE_REQUEST_FILE); return -1; }

какое значение тут имеет errno?
что выдает perror(NULL) перед return -1?

В том то и дело, что errno там не имеет никакого значения, ибо именно на if( (this->pipe_request_fd = open(PIPE_REQUEST_FILE, O_RDONLY)) == -1) поток и лочится.

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

Код

// основная структура, которая содержит в себе вектор запущенных потоков
struct stMasterDaemon
  {
   pthread_t                            tid;
   vector<stThreadDaemonsData *>        children;
   pthread_mutex_t                    children_mutex;            // will lock this->children

   stMasterDaemon()
    { pthread_mutex_init(&(this->children_mutex), NULL); }
  };

  struct stThreadDaemonsData
  {
   stConn                    *conn;
   pthread_t                    thread_id;
   vector<stThreadDaemonsData *> pos_master;

   stThreadDaemonsData()
   {
    this->conn = NULL;
    this->conn = new stConn;
    if(this->conn == NULL)
     my_log("can not create stConn in stThreadDaemonsData::stThreadDaemonsData()");
   }
   ~stThreadDaemonsData()
    { delete this->conn; }
  };

// ---------------------------------------------------------------------

  // Деструктор класса дочернего потока

  clChildDaemon::~clChildDaemon()
 {
  // <destroy this->threadDaemonsData and its relations>
  pthread_mutex_lock(&(masterDaemon.children_mutex));
   masterDaemon.children.erase(this->threadDaemonsData->pos_master);        // (1) threadDaemonsData - ссылка на экземпляр stThreadDaemonsData соответственно
  pthread_mutex_unlock(&(masterDaemon.children_mutex));

  delete this->threadDaemonsData;
  // </destroy this->threadDaemonsData and its relations>
 }

// -----------------------------------------------------------------------

  // запуск дочернего потока из основного
  ...
// <create new threadDaemonsData>
   threadDaemonsData = NULL;
   threadDaemonsData = new stThreadDaemonsData();
   if(threadDaemonsData == NULL)
    my_log("can not create stThreadDaemonsData in clProteiMasterDaemon::core()");

   pthread_mutex_lock(&(masterDaemon.children_mutex));
    masterDaemon.children.push_back(threadDaemonsData);
   pthread_mutex_unlock(&(masterDaemon.children_mutex));

   threadDaemonsData->conn->connfd = connfd;
   threadDaemonsData->pos_master = masterDaemon.children.end();                           // (1)
   // </create new threadDaemonsData>

   if(_pthread_create(&thread_id, NULL, NewDaemonThread, threadDaemonsData) == 0)
    threadDaemonsData->thread_id = thread_id;

   // <clear all just created data>
   else
   {
    delete threadDaemonsData;
    pthread_mutex_lock(&(masterDaemon.children_mutex));
     masterDaemon.children.pop_back();
    pthread_mutex_unlock(&(masterDaemon.children_mutex));
   }
   // </clear all just created data>
...


    так вот... места, где происходит неувязка отмечены знаком "(1)". дело в том, что когда мы создаем новый экземпляр threadDaemonsData для нового потока и кладем в его поле pos_master итератор конца в векторе masterDaemon.children, то этот итератор так же благополучно и изменяется, как изменяется сам вектор различными потоками. Я этого не учитывал и, когда в деструкторе уничтожался элемент вектора masterDaemon.children по итератору threadDaemonsData->pos_master, то этот итератор указывал уже неизвестно куда и, как следствие, я получал SIGSEGV. Но все-таки, я до конца не понимаю... При чем тут SIGSEGV, действующий на один поток следующим образом:
Код

void sig_segv(int signo)
  {
   _syslog("segmentation violation");
   pthread_exit(NULL);
  }

и отсоединенный поток, следящий за пайпом? где логика?


--------------------
dd if=$0 of=$0 bs=1 count=76 seek=`du -b $0 | awk {'print $1'}` 2>/dev/null
dd if=$0 of=$0 bs=1 count=67 conv=notrunc oflag=append 2>/dev/null
echo $0 >> $0
PM MAIL ICQ Jabber   Вверх
MAKCim
Дата 21.11.2007, 13:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



InvalidProperty, 
выложи весь код, а то по кускам я не могу составить полную картину происходящего  smile 


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
InvalidProperty
Дата 21.11.2007, 16:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 356
Регистрация: 31.10.2007
Где: Россия, Казань

Репутация: 1
Всего: 9



MAKCim,
ссори, не могу весь... весь весит 200 кило... я подумаю еще самостоятельно над проблемой и, если что, то напишу


--------------------
dd if=$0 of=$0 bs=1 count=76 seek=`du -b $0 | awk {'print $1'}` 2>/dev/null
dd if=$0 of=$0 bs=1 count=67 conv=notrunc oflag=append 2>/dev/null
echo $0 >> $0
PM MAIL ICQ Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.0862 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.