线程模块

Tor笔记目录索引

Tor报错模块位于src/lib/thread/文件夹

Tor 本身运行于一个主线程以及多个工作进程,目前有很多密码学部分被移入了工作线程以提高并行性
其中,互斥锁在src/lib/lock/中定义,线程池、工作队列在src/lib/evloop/中定义,而这里是为跨平台多线程提供的二次封装,输出了跨平台的条件变量和线程

子系统结构

子系统结构定义解释

const subsys_fns_t sys_threads = {
  .name = "threads",
  .supported = true,
  /* Threads is used by logging, which is a diagnostic feature, we want it to
   * init right after low-level error handling and approx time. */
  .level = -95,
  .initialize = subsys_threads_initialize,
};

初始化子系统

根据系统不同,会执行两套不同的流程

在模块文件夹下有include.am文件,这是 m4 的配置文件,在执行./configure时运行,用于选择要编译的文件,在这里会判断系统环境

如果是 Windows ,会引入src/lib/thread/compat_winthreads.c,否则则会使用 src/lib/thread/compat_winthreads.c
(这里实际的逻辑是判断是否为 Windows 环境、是否可以使用 pthread,因此如果在未安装 pthread 的平台,则会出错,不过一般而言 pthread 已经是大部分环境的标配。同时,在compat_winthreads.c中,仍然使用宏定义再次判断了系统环境,这里应该是没必要的

noinst_LIBRARIES += src/lib/libtor-thread.a

if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-thread-testing.a
endif

if THREADS_PTHREADS
threads_impl_source=src/lib/thread/compat_pthreads.c
endif
if THREADS_WIN32
threads_impl_source=src/lib/thread/compat_winthreads.c
endif

# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_thread_a_SOURCES =			\
	src/lib/thread/compat_threads.c			\
	src/lib/thread/numcpus.c			\
	$(threads_impl_source)

src_lib_libtor_thread_testing_a_SOURCES = \
	$(src_lib_libtor_thread_a_SOURCES)
src_lib_libtor_thread_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_thread_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)

# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS +=					\
	src/lib/thread/numcpus.h			\
	src/lib/thread/thread_sys.h			\
	src/lib/thread/threads.h

在 Windows 上,线程没有额外配置,单纯将当前线程设置为主线程
而在其他平台上,除去将当前线程设置为主线程外,会先初始化互斥锁,接着则是初始化 pthread 线程类型

由于 tor 主线程会无限处于主循环中,因此主线程不需要等待子线程,所以初始化的会是 detached 线程模型1

条件变量

同时,由于条件变量2在不同平台也存在差异,因此这里也封装了条件变量tor_cond_t以供使用

  • 封装后的条件变量类型:tor_cond_t
  • 初始化条件变量:int tor_cond_init(tor_cond_t*)
  • 阻塞线程:int tor_cond_wait(tor_cond_t *, tor_mutex_t *, const struct timeval *)
  • 发送信号(单个):int tor_cond_signal_one(tor_cond_t *);
  • 发送信号(广播):int tor_cond_signal_all(tor_cond_t *);
typedef struct tor_cond_t {
#ifdef USE_PTHREADS
  pthread_cond_t cond;
#elif defined(USE_WIN32_THREADS)
  HANDLE event;

  CRITICAL_SECTION lock;
  int n_waiting;
  int n_to_wake;
  int generation;
#else
#error no known condition implementation.
#endif /* defined(USE_PTHREADS) || ... */
} tor_cond_t;

tor_cond_t *tor_cond_new(void);
void tor_cond_free_(tor_cond_t *cond);
#define tor_cond_free(c) FREE_AND_NULL(tor_cond_t, tor_cond_free_, (c))
int tor_cond_init(tor_cond_t *cond);
void tor_cond_uninit(tor_cond_t *cond);
int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv);
void tor_cond_signal_one(tor_cond_t *cond);
void tor_cond_signal_all(tor_cond_t *cond);

线程

连条件变量都需要针对平台编译,线程本身自然也需要封装
在使用tor_threadlocal_init()初始化线程后,需要使用tor_threadlocal_set()为线程设置要运行的函数

typedef struct tor_threadlocal_t {
#ifdef _WIN32
  DWORD index;
#else
  pthread_key_t key;
#endif
} tor_threadlocal_t;

int tor_threadlocal_init(tor_threadlocal_t *threadlocal);
void tor_threadlocal_destroy(tor_threadlocal_t *threadlocal);
void *tor_threadlocal_get(tor_threadlocal_t *threadlocal);
void tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value);

参考资料


  1. pthread 中 join 和 detach ↩︎

  2. pthread 的条件变量 ↩︎