Причина неудачи ENOMEM для создания потоков? - PullRequest
2 голосов
/ 25 декабря 2010

У меня есть приложение, которое использует pthread_create() и pthread_detach() в основном потоке, а затем pthread_exit() в дочернем потоке.

После примерно 54 pthread_create() вызовов, каждый из которых был связан споследующий pthread_detach(), а затем pthread_exit() pthread_create() завершается неудачей.Это ENOMEM ошибка «Недостаточно памяти».

Что может привести к тому, что pthread_exit() не освободит память старых потоков и не приведет к утечке памяти моим приложением и, в конечном итоге, к его исчерпанию?

Это работает в Linux Centos 5 64-битное, но 32-битное приложение.

Вот код для создания потока, который вызывает и pthread_create(), и pthread_detach().

int
_createThread()
{
  pthread_attr_t attr;
  int return_val;

  return_val = setupMutex(_Mtx());

  if (return_val != 0) {
    return return_val;
  }

  return_val = setupCond(_StartCond());

  if (return_val != 0) {
    return return_val;
  }

  return_val = setupCond(_EndCond());

  if (return_val != 0) {
    return return_val;
  }

  return_val = pthread_attr_init(&attr);

  if (return_val != 0) {
    return -1;
  }

  size_t stackSize = 1024 * 1024 * 64; // Our default stack size 64MB.

  return_val = pthread_attr_setstacksize(&attr, stackSize);

  if (return_val != 0) {
    return -1;
  }

  int tries = 0;

 retry:
  // _initialize() gets called by the thread once it is created.
  return_val = pthread_create(&_threadId, &attr,
                              (void *(*)(void *))_initialize,
                              (void *)this);

  if (return_val != 0) {
    if (return_val == EAGAIN) {
      if (++tries < 10) {
        Exit::deferredWarning(Exit::eagainThread);
        goto retry;
      }
    }
    return -1;
  }

  return_val = pthread_attr_destroy(&attr);

  if (return_val != 0) {
    return -1;
  }

  return_val = pthread_detach(_threadId);

  if (return_val != 0) {
    return -1;
  }

  // Wait for the new thread to finish starting up.
  return_val = waitOnCond(_Mtx(), _EndCond(), &_endCount, 10 /* timeout */, 0,
                          "_createThread-end");

  if (return_val != 0) {
    return -1;
  }

  return 0;
}

void
_exitThread()
{
  (void) releaseCond(_Mtx(), _EndCond(), &_endCount, "_exitThread-end");
  pthread_exit(NULL);
}

Ответы [ 4 ]

4 голосов
/ 25 декабря 2010

Вызовите pthread_join до pthread_exit , чтобы поток мог очиститься перед выходом.

2 голосов
/ 25 августа 2016

Объяснение приведено в справочной странице pthread_create :

Когда отключенный поток завершается, его ресурсы автоматически возвращаются обратно в систему без необходимости в другом потоке дляприсоединиться к завершенному потоку

Так что, если вы не отсоедините его и не присоединитесь к нему, вы потеряете некоторые ресурсы, которые в конечном итоге вызовут ENOMEM.

Вы должны отсоединить поток или присоединить его к егородительский поток.

1 голос
/ 28 декабря 2010

Уилл, я удалил свой старый ответ, потому что кажется, что я ошибся.В связи с этим у меня есть вопрос: как вы получили ENOMEM?Вы проверили «errno», как я указал в моем ответе?Потому что pthread_create является исключением из правила и не устанавливает errno;вместо этого в результате возвращается ошибка.

Правильный способ получения причины сбоя:

int err = pthread_create(...);
if(err)
{
    perror( "Error creating thread" );
    printf( "Error: %s\n", strerror( err ) );
    return false;
}

Причина, по которой я спрашиваю, заключается в том, что pthread_create никогда не завершится с ENOMEM!В случае отсутствия памяти pthread_create вернет EAGAIN.Обратитесь к http://sourceware.org/ml/glibc-bugs/2007-11/msg00007.html для получения информации о EAGAIN vs ENOMEM

EDIT

Очевидный вопрос: системе действительно достаточно памяти слева, верно?

0 голосов
/ 15 февраля 2016

вызов pthread_join() или, альтернативно, pthread_detatch(), если объединение не работает для вашего варианта использования.

эта ошибка возникает из-за того, что библиотека хранит коды завершения всех завершенных потоков, ожидая, чтобы передать их вам обратно через pthread_join(). в качестве альтернативы, если вам не важен код выхода потока, вызовите pthread_detatch() после его создания. это говорит API, что вы не заботитесь о его коде возврата, поэтому ему не нужно его хранить.

...