线程支持
C11 引入标准线程支持 <threads.h>,提供跨平台的线程创建、同步、互斥等功能。在此之前,线程支持依赖平台特定 API(POSIX pthreads、Windows threads)。C11 线程库简化了多线程编程,但支持程度取决于编译器和平台。
基本线程创建
#include <threads.h>
#include <stdio.h>
int thread_func(void *arg)
{
int num = *(int *)arg;
printf("Thread %d running\n", num);
return 0;
}
int main(void)
{
thrd_t thread;
int arg = 1;
if (thrd_create(&thread, thread_func, &arg) == thrd_success) {
thrd_join(thread, NULL); /* 等待线程结束 */
}
return 0;
}
互斥锁
#include <threads.h>
static mtx_t mutex;
static int counter = 0;
int increment(void *arg)
{
for (int i = 0; i < 1000; i++) {
mtx_lock(&mutex);
counter++;
mtx_unlock(&mutex);
}
return 0;
}
int main(void)
{
mtx_init(&mutex, mtx_plain);
thrd_t t1, t2;
thrd_create(&t1, increment, NULL);
thrd_create(&t2, increment, NULL);
thrd_join(t1, NULL);
thrd_join(t2, NULL);
printf("Counter: %d\n", counter); /* 2000 */
mtx_destroy(&mutex);
return 0;
}
条件变量
#include <threads.h>
static mtx_t mutex;
static cnd_t cond;
static int ready = 0;
int worker(void *arg)
{
mtx_lock(&mutex);
while (!ready) {
cnd_wait(&cond, &mutex); /* 等待条件 */
}
printf("Worker proceeding\n");
mtx_unlock(&mutex);
return 0;
}
int main(void)
{
mtx_init(&mutex, mtx_plain);
cnd_init(&cond);
thrd_t worker_thread;
thrd_create(&worker_thread, worker, NULL);
/* 模拟工作 */
thrd_sleep(&(struct timespec){.tv_sec = 1}, NULL);
mtx_lock(&mutex);
ready = 1;
cnd_signal(&cond); /* 通知等待线程 */
mtx_unlock(&mutex);
thrd_join(worker_thread, NULL);
mtx_destroy(&mutex);
cnd_destroy(&cond);
return 0;
}
线程局部存储
_Thread_local int thread_local_var; /* C11 */
/* 或 */
thread_local int tls_var; /* <threads.h> 宏 */
兼容性
/* 如果编译器不支持 C11 threads */
#ifdef __STDC_NO_THREADS__
/* 使用平台特定 API */
#include <pthread.h>
/* ... */
#else
#include <threads.h>
/* ... */
#endif
常见错误
忘记解锁:
mtx_lock(&mutex);
/* 操作 */
if (error())
return -1; /* 错误:未解锁就返回 */
mtx_unlock(&mutex);
/* 正确 */
mtx_lock(&mutex);
/* 操作 */
mtx_unlock(&mutex);
if (error())
return -1;
条件变量虚假唤醒:
/* 错误 */
if (!ready) { /* 应该用 while */
cnd_wait(&cond, &mutex);
}
/* 正确 */
while (!ready) { /* 防止虚假唤醒 */
cnd_wait(&cond, &mutex);
}
最佳实践
- 锁的粒度尽量小
- 用
while而非if检查条件变量 - 避免死锁(统一加锁顺序)
- 线程局部存储减少共享数据
- 考虑无锁数据结构