Страниц: [1] 2
  Печать  
Автор Тема: Поток в программе при завершении становится зомби  (Прочитано 4616 раз)
Дмитрий
Участник
*
Offline Offline

Сообщений: 38


Просмотр профиля
« : Августа 18, 2015, 01:38:18 pm »

Здравствуйте!

Столкнулся со следующей проблемой:

Есть поток, запускаемый в программе
Код:
char      *stack_s;
char      *args_s[3];
......
  stack_s = (char *) malloc( STACK_SIZE );
.......
функция, вызываемая, что бы запустить поток:
int sound_(void)
{
if(flag==1)
{
        _beginthread( thread_s, stack_s, STACK_SIZE, args_s );
}
return 0 ;
}
void thread_s( void *parm )
  {
 
dspout = open( "/dev/dsp", O_WRONLY | O_NOCTTY );
in_fd = open(fl_s, O_RDONLY | O_NOCTTY );

   if(( in_fd !=-1)&&(dspout!=-1))
    {
     
     while ((actlen = read ( in_fd, buf_s, BUF_SIZE )) > 0) write (dspout,buf_s,actlen);
     }              
  close(in_fd);    
  close (dspout);
   flag =0;  
 _endthread();
  }
/* --------------------------------------------- */

при запуске программы, при вызове функции sound_, в системе появляется по одному ZOMBIE, пока основная программа не завершится!
Если я комментирую _beginthread, то зомби в системе нет.
Что я делаю не корректно, ведь в документации сказано, что поток должен завершаться функцией _endthread ?
Важная вещь: программа запускается под VirtualBox, система QNX4.2. Вывод процессов осуществляется графической функцией sin.
« Последнее редактирование: Августа 18, 2015, 02:41:19 pm от Дмитрий » Записан
Dark
Sr. Member
****
Offline Offline

Сообщений: 343


Просмотр профиля
« Ответ #1 : Августа 18, 2015, 02:45:33 pm »

В четверке нет потоков - это процессы. "Окей, гугл! Что такое процесс-зомби?".
Записан
darkelf
QOR.Moderator
*****
Offline Offline

Сообщений: 256


Просмотр профиля
« Ответ #2 : Августа 18, 2015, 02:54:22 pm »

Здравствуйте!

Столкнулся со следующей проблемой:
Есть поток, запускаемый в программе
при запуске программы, при вызове функции sound_, в системе появляется по одному ZOMBIE.
Если я комментирую _beginthread, то зомби в системе нет.
Что я делаю не корректно, ведь в документации сказано, что поток должен завершаться функцией _endthread ?
Важная вещь: программа запускается под VirtualBox, система QNX4.2. Вывод процессов осуществляется графической функцией sin.

Насколько я помню, потоки в QNX4 не являются полнофункциональными - на самом деле это процессы, которые разделяют общее адресное пространство.
Если поискать по архивам форума, то можно найти такое обсуждение.

Я не уверен, но можно попробовать сделать следующее - идентификатор потока, возвращаемый функцией _beginthread() передать на ожидание функции wait() или waitpid(), но это в документации не описано и будет работать или нет - не известно.
Записан
Dark
Sr. Member
****
Offline Offline

Сообщений: 343


Просмотр профиля
« Ответ #3 : Августа 18, 2015, 04:40:01 pm »

Вероятно, зомби лезут на звук. Отстреливайтесь!!!
Записан
deadarcher
Jr. Member
**
Offline Offline

Сообщений: 70



Просмотр профиля
« Ответ #4 : Августа 19, 2015, 12:13:43 am »

по уму при завершении потока должон приходить SIGCHLD
в обработчике сигнала вызвать waitpid(0,NULL,WNOHANG)
или же заместо _endthread() триггерить проксю, по которой в основном процессе (потоке) вызывать всё тот жа waitpid.
накрайняк просто периодически в main вызывать waitpid(0,NULL,WNOHANG)
не знаю как в документации - у меня проверено опытом  Wink

и следите за стэком - основной подводный камень. для каждого потока должен быть свой уникальный стек.
если маллоком один раз выделить память, а потоков одновременно запущенно будет больше чем один - результат не предсказуем. в том куске кода, что приведён в первом посте, есть вероятность такого:
вызвали sound_(), файл оказался большим а запись идет неспеша - флаг так и не скинулся в 0, вызвали второй раз саунд - и вот уже два потока работают. ну как то так.  Huh?
кароч с потоками нада оч аккуратно - а то придет великий и ужасный ... сигсегв  Smiley
« Последнее редактирование: Августа 19, 2015, 12:36:42 am от deadarcher » Записан
deadarcher
Jr. Member
**
Offline Offline

Сообщений: 70



Просмотр профиля
« Ответ #5 : Августа 19, 2015, 12:18:57 am »

в 4рке поток не обязательно завершать _endthread() - достаточно return
единственно где имеет смысл - это если мы находимся в обработчике сигналов, по getpid() определили что мы в потоке и словили сигнал по которому нада завершить поток, вот тогда _endthread() необходим.

Записан
Дмитрий
Участник
*
Offline Offline

Сообщений: 38


Просмотр профиля
« Ответ #6 : Августа 19, 2015, 04:52:21 pm »

Здравствуйте!

Посмотрел все советы и решил ограничится одним потоком, просто из main передавать ему соответствующие параметры по флагам,
а поток в бесконечном ожидании с паузами, чтобы не загружать систему, во время бесконечного цикла.

Код:
void thread_s( void *parm )
  {
    pid_t proxy;
    timer_t id;
    struct itimerspec timer;
    struct sigevent event;

    proxy = qnx_proxy_attach( 0, 0, 0, -1 );
    event.sigev_signo = -proxy;
    id = timer_create( CLOCK_REALTIME, &event );
    timer.it_value.tv_sec     = 1L;
    timer.it_value.tv_nsec    = 0L;
    timer.it_interval.tv_sec  = 0L;
    timer.it_interval.tv_nsec = 1000000L;
    timer_settime( id, 0, &timer, NULL );

  
    while(!end_flag){

Receive( proxy, 0, 0 );

if (SoundEnable==1)
{
 dspout = open( "/dev/dsp", O_WRONLY | O_NOCTTY );
 in_fd = open(fl_s, O_RDONLY | O_NOCTTY );
 
  if(( in_fd !=-1)&&(dspout!=-1))
    {
     
     while ((actlen = read ( in_fd, buf_s, BUF_SIZE )) > 0) write (dspout,buf_s,actlen);
     }              
 
    close(in_fd);  
    close (dspout);

SoundEnable=0;

}    
}
     _endthread();
 
  }
« Последнее редактирование: Августа 19, 2015, 05:01:48 pm от Дмитрий » Записан
deadarcher
Jr. Member
**
Offline Offline

Сообщений: 70



Просмотр профиля
« Ответ #7 : Августа 19, 2015, 06:20:12 pm »

А сейчас я позволю себе сказать как умею  Smiley
Чета мени кажется, что када таймер через секунду начнет фигачить с интервалом в 1мс, не особо это гуд.   Sad
Куда красивее сделать проксю глобальной и её триггерить - так гораздо системе менее напряжно.  Wink

И берем за правило: када объявляем пиды, прокси, таймеры, дескрипторы - приравнивать их к минус единице (-1). После закрытия дескритора, удаления таймера, освождения прокси - приравнять к -1. При объявлении указателя и после его освобождения - приравнять к NULL.

pid_t thr_proxy=-1;
int dspout=-1;
timer_t tmr_id=-1;
...
close(dspout); dspout=-1;
timer_delete(tmr_id); tmr_id=-1;
надеюсь идея понятна Smiley

И не забываем проверять всякие open/creat/attach/malloc и т.д. на ошибки с документированием errno (в критициских местах естественно)
« Последнее редактирование: Августа 19, 2015, 06:37:00 pm от deadarcher » Записан
Дмитрий
Участник
*
Offline Offline

Сообщений: 38


Просмотр профиля
« Ответ #8 : Августа 20, 2015, 10:45:02 am »

Здравствуйте!

Решил по Вашему совету триггить прокси. Для этого написал тестовою программу,
но она не работает. Где ошибка? По программе один поток раз в 1 сек.вызывает
Trigger() прокси, а второй выводит Tick на экран каждую сек. Но код нее работает(((
Код:
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/proxy.h>
#include <sys/kernel.h>
#include <stdlib.h>
#include <unistd.h>


#define STACK_SIZE   8192
 char c,flag=0;
pid_t proxy_trigger;


void thread_proxy( void *parm )
  {
      while(flag==0){
      Receive( proxy_trigger, 0, 0 );
      printf( "Tick.\n" );
    }
 _endthread();
  }

void thread( void *parm )
  {
    pid_t proxy;
    timer_t id, i;
    struct itimerspec timer;
    struct sigevent event;

    proxy = qnx_proxy_attach( 0, 0, 0, -1 );
 
    event.sigev_signo = -proxy;
    id = timer_create( CLOCK_REALTIME, &event );
 
    timer.it_value.tv_sec     = 1L;
    timer.it_value.tv_nsec    = 0L;
    timer.it_interval.tv_sec  = 1L;
    timer.it_interval.tv_nsec = 0L;
    timer_settime( id, 0, &timer, NULL );

      while(flag==0){
      Receive( proxy, 0, 0 );
      Trigger(proxy_trigger);     
    }

    timer_delete( id );
 _endthread();
  }




int main( void )
  {
char      *args[3];
char      *stack;
char      *stack_t;

  proxy_trigger = qnx_proxy_attach( 0, 0, 0, -1 );
 
  printf("Press q to exit \n");
       
  stack = (char *) malloc( STACK_SIZE );
  stack_t = (char *) malloc( STACK_SIZE );
     
        _beginthread( thread, stack, STACK_SIZE, args );
        _beginthread( thread_proxy, stack_t, STACK_SIZE, args );

  while (c!='q')
{
  c=getch();
}
flag=1;
sleep(1);
    return( EXIT_SUCCESS );
  }

Записан
darkelf
QOR.Moderator
*****
Offline Offline

Сообщений: 256


Просмотр профиля
« Ответ #9 : Августа 20, 2015, 12:31:58 pm »

Сорри, давно не работаю с QNX, так-что могу ошибаться, надеюсь остальные посетители форума меня поправят, если буду не прав. Мне кажется, что Вы подключаете proxy к основному потоку, который выполняет main(), а не к потоку, который выполняет thread_proxy(). В документации написано, что proxy trig-нуть может кто угодно, но получить этот самый trig - только тот процесс, к которому подключена proxy.
Записан
Дмитрий
Участник
*
Offline Offline

Сообщений: 38


Просмотр профиля
« Ответ #10 : Августа 20, 2015, 01:34:33 pm »

Спасибо за ответ, но только вопрос в том, как передать потоку proxy?
Записан
qnx_user
Full Member
***
Offline Offline

Сообщений: 113


Просмотр профиля
« Ответ #11 : Августа 20, 2015, 01:56:54 pm »

Спасибо за ответ, но только вопрос в том, как передать потоку proxy?

Вот пример в листинге (код-скелетик состряпал из ранее написанного кода, лишнее поудалял). Единственное что в нем может стопорнуть это вызов нестандартной функции thread_registration для создания потока (но это в данном случае не так важно), главное что прокси передается потоку (по приходу прерывания) без всяких проблем. Может поможет Smiley
Код:

#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/proxy.h>
#include <sys/kernel.h>
#include <stdlib.h>
#include <unistd.h>
...

static bool exe   = false; // флаг работы основного процесса
static bool thexe = false; // флаг работы приемной нити

static pid_t gProxy = -1;
int          idIrq      = -1; // identifier of interrupt handler

static char thread_stack[8192] = { 0 }; //стек для нити-приемника

// Обработка сигнала SIGKILL
static void KillProc()
{
exe = thexe = false;
}

#pragma off(check_stack)
static pid_t __far InterruptHandler()
{
        ...
  return gProxy;
}
#pragma on(check_stack)

static int thread_proxy( void *arg )
{
// Get a proxy for the interrupt handler to kick
gProxy = qnx_proxy_attach( 0, 0, 0, -1 );
if( -1 == gProxy ) {
printf( "Unable to attach proxy." );
return 0;
}

thexe = true;

while ( thexe )
{
Receive( gProxy, 0, 0 );

...
}
_endthread();

return 0;
}

static bool Init( char *arg[] )
{
const char * const appName = arg[0]; // имя программы

// Attach`им функцию обработки к прерыванию
idIrq = qnx_hint_attach( canIRQ, &InterruptHandler, my_ds() );
if ( -1 == idIrq ) {
// Возможно из-за отсутствия прав!!!
printf( "%s: не удалось присоеденить функцию обработки к прерыванию IRQ%d.\n", appName, canIRQ );
return false;
}

// Запускаем подчиненную нить, для чтения с устройства.
thread_registration( 1, thread_stack, sizeof(thread_stack), thread_proxy );

return true;
}
 
int main( int argc, char *argv[] )
{
const char * const appName = argv[0]; // имя программы

// Привязываем процедуру обработки к сигналу
qnx_pflags( _PPF_IMMORTAL, _PPF_IMMORTAL, NULL, NULL );
signal( SIGKILL, KillProc );

if ( Init(argv) )
exe = true;

while ( exe )
{
...
}

qnx_hint_detach( idIrq );

return 0;
}
« Последнее редактирование: Августа 20, 2015, 03:53:59 pm от qnx_user » Записан
Дмитрий
Участник
*
Offline Offline

Сообщений: 38


Просмотр профиля
« Ответ #12 : Августа 20, 2015, 02:16:34 pm »

Спасибо!!!
Сделал так, и все пошло:

Код:
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/proxy.h>
#include <sys/kernel.h>
#include <stdlib.h>
#include <unistd.h>


#define STACK_SIZE   8192
 char c,flag=0;
pid_t proxy_trigger = -1;


void thread_proxy( void *parm )
  {   proxy_trigger = qnx_proxy_attach( 0, 0, 0, -1 ); //proxy инициализируем здесь.
      while(flag==0){
      Receive( proxy_trigger, 0, 0 );
      printf( "Tick.\n" );
    }
 _endthread();
  }

void thread( void *parm )
  {
    pid_t proxy;
    timer_t id, i;
    struct itimerspec timer;
    struct sigevent event;

    proxy = qnx_proxy_attach( 0, 0, 0, -1 );
  
    event.sigev_signo = -proxy;
    id = timer_create( CLOCK_REALTIME, &event );
  
    timer.it_value.tv_sec     = 1L;
    timer.it_value.tv_nsec    = 0L;
    timer.it_interval.tv_sec  = 1L;
    timer.it_interval.tv_nsec = 0L;
    timer_settime( id, 0, &timer, NULL );

      while(flag==0){
      Receive( proxy, 0, 0 );
      Trigger(proxy_trigger);      
    }

    timer_delete( id );
 _endthread();
  }




int main( void )
  {
char      *args[3];
char      *stack;
char      *stack_t;

  // а не здесь!!!
  
 printf("Press q to exit \n");
        
 stack = (char *) malloc( STACK_SIZE );
 stack_t = (char *) malloc( STACK_SIZE );
      
        _beginthread( thread, stack, STACK_SIZE, args );
        _beginthread( thread_proxy, stack_t, STACK_SIZE, args );

 while (c!='q')
{
 c=getch();
}
flag=1;
sleep(1);
    return( EXIT_SUCCESS );
  }

« Последнее редактирование: Августа 20, 2015, 02:55:47 pm от Дмитрий » Записан
deadarcher
Jr. Member
**
Offline Offline

Сообщений: 70



Просмотр профиля
« Ответ #13 : Августа 20, 2015, 03:42:19 pm »

Ну вы блин даёте  Smiley
Поясняю смысел: объявляем глобальную проксю th_proxy, запускаем поток. в потоке аттачим проксю, встаем в потоке на ресив. функция sound_() содержит один единственный вызов Trigger(th_proxy).
Cча код нарисую.
Записан
qnx_user
Full Member
***
Offline Offline

Сообщений: 113


Просмотр профиля
« Ответ #14 : Августа 20, 2015, 03:50:37 pm »

Поясняю смысел: объявляем глобальную проксю th_proxy, запускаем поток. в потоке аттачим проксю, встаем в потоке на ресив.
Именно так и сделано выше.

функция sound_() содержит один единственный вызов Trigger(th_proxy).
а это детали реализации (в моем коде поток необходимо было запускать по прерыванию).
« Последнее редактирование: Августа 20, 2015, 03:53:08 pm от qnx_user » Записан
Страниц: [1] 2
  Печать  
 
Перейти в: