nodejs建立线程问题

咱们知道在nodejs中可使用new Worker建立线程。今天有个同窗刚好问到,怎么判断建立线程成功,这也是最近开发线程池的时候遇到的问题。nodejs文档里也没有提到如何捕获建立失败这种状况。因此只能经过源码去找答案。不过坏消息是,咱们没法捕获这个这个错误。下面看一下源码。咱们直接从c++层开始分析。
   当咱们调用new Worker的时候,最后会调用c++的StartThread函数(node_worker.cc)建立一个线程。node

CHECK_EQ(uv_thread_create_ex(&w->tid_, &thread_options, [](void* arg) {
    // ...
  }, static_cast<void*>(w)), 0);

咱们看uv_thread_create_ex的逻辑linux

int uv_thread_create_ex(uv_thread_t* tid,
                        const uv_thread_options_t* params,
                        void (*entry)
(void *arg),
                        void *arg) 
{
  // 忽略部分代码
  err = pthread_create(tid, attr, f.out, arg);
  return UV__ERR(err);
}

接着咱们看一下pthread_create的返回值定义c++

On success, pthread_create() returns 0; on error, it returns an error
      number, and the contents of *thread are undefined.web

因此,若是uv_thread_create_ex返回非0,即pthread_create返回非0。表示报错。咱们回头看一下返回非0时,c++的处理。咱们对c++层的CHECK_EQ(uv_thread_create_ex(…), 0)进行宏展开。编程

#define CHECK_EQ(a, b) CHECK((a) == (b))

#define CHECK(expr)                                                           \
  do {                                                                        \
    if (UNLIKELY(!(expr))) {                                                  \
      ERROR_AND_ABORT(expr);                                                  \
    }                                                                         \
  } while (0)


#define UNLIKELY(expr) expr

经过一些列展开,最后变成微信

  do {                                                                        
    if (!(返回值 == 0)) {                                                  
      ERROR_AND_ABORT(expr);                                                  
    }                                                                         
  } while (0)

由于建立线程时返回非0,因此这里是true。咱们继续看ERROR_AND_ABORT多线程

#define ERROR_AND_ABORT(expr)                                                 \
  do {                                                                

    static const node::AssertionInfo args = {                                 \
      __FILE__ ":" STRINGIFY(__LINE__), #expr, PRETTY_FUNCTION_NAME           \
    };                                                                        \
    node::Assert(args);                                                       \
  } while (0)

拼接错误信息,而后执行node::Assert(args);less

[[noreturn]] void Assert(const AssertionInfo& info) {
  char name[1024];
  GetHumanReadableProcessName(&name);

  fprintf(stderr,
          "%s: %s:%s%s Assertion `%s' failed.\n",
          name,
          info.file_line,
          info.function,
          *info.function ? ":" : "",
          info.message);
  fflush(stderr);

  Abort();
}

重点是Abort,函数

[[noreturn]] void Abort() {
  DumpBacktrace(stderr);
  fflush(stderr);
  ABORT_NO_BACKTRACE();
}

继续看ABORT_NO_BACKTRACE测试

#ifdef _WIN32
#define ABORT_NO_BACKTRACE() _exit(134)
#else
#define ABORT_NO_BACKTRACE() abort()
#endif

因此最终调用的是_exit或abort退出或者终止进程。咱们讨论linux下的状况。咱们看abort函数的说明

The abort() function first unblocks the SIGABRT signal, and then
      raises that signal for the calling process (as though raise(3) was
      called).  This results in the abnormal termination of the process
      unless the SIGABRT signal is caught and the signal handler does not
      return (see longjmp(3)).
      If the SIGABRT signal is ignored, or caught by a handler that
      returns, the abort() function will still terminate the process.  It
      does this by restoring the default disposition for SIGABRT and then
      raising the signal for a second time.

abort函数会给进程发送SIGABRT信号,咱们能够注册函数处理这个信号,不过咱们仍是没法阻止进程的退出,由于他执行完咱们的处理函数后,会把处理函数注册为系统的默认的,而后再次发送SIGABRT信号,而默认的行为就是终止进程。咱们来个测试。

const { Worker, threadId } = require('worker_threads');
for (let i = 0; i < 1000; i++) {
    const worker = new Worker('var a = 1;', { eval: true });
}

咱们建立1000个线程。结果


总结:在nodejs建立过多的线程可能会致使进程终止。而咱们没法阻止这个行为。因此在nodejs里使用多线程的时候,咱们须要注意的就是不要开启过多的线程,而在建立线程的时候,咱们也不须要关注是否成功,由于只要进程不挂掉,那就是成功。对于业务错误咱们能够注册error事件处理,在new Worker的时候,咱们能够加try catch。能够捕获一下参数错误的状况。

本文分享自微信公众号 - 编程杂技(theanarkh)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索