pthread_create 是 POSIX 线程(Pthreads)库中用于创建新线程的核心函数,它定义在 <pthread.h> 头文件中。

(图片来源网络,侵删)
函数原型
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
参数详解
这个函数接受四个参数,我们来逐一分解:
参数 1: pthread_t *thread
- 类型: 指向
pthread_t对象的指针。 - 作用: 这是一个输出参数,当
pthread_create成功创建一个新线程后,系统会为新线程生成一个唯一的 ID,并将这个 ID 存储在你传入的pthread_t变量中。 - 后续用途: 你可以使用这个线程 ID 来对线程进行其他操作,比如等待线程结束(
pthread_join)、分离线程(pthread_detach)等。 - 示例:
pthread_t my_thread_id; pthread_create(&my_thread_id, NULL, my_function, NULL);
参数 2: const pthread_attr_t *attr
- 类型: 指向
pthread_attr_t结构体的常量指针。 - 作用: 用于指定新线程的属性,线程的栈大小、调度策略、是否分离等。
- 常用值:
NULL: 这是最常用的值,它表示使用线程的默认属性,对于绝大多数简单应用来说,默认属性就足够了。
- 自定义属性: 如果你需要设置特定属性,你需要先初始化一个属性对象,然后使用
pthread_attr_init,pthread_attr_setstacksize等函数来修改它,最后将这个对象的地址传给pthread_create。 - 示例:
pthread_create(&my_thread_id, NULL, my_function, NULL); // 使用默认属性
参数 3: void *(*start_routine)(void *)
-
类型: 一个函数指针。
-
作用: 这是新线程一旦被创建就会立即执行的函数的地址,这个函数也被称为线程的入口函数或启动例程。
-
函数签名要求:
(图片来源网络,侵删)- 它必须接受一个
void *类型的参数。 - 它必须返回一个
void *类型的值。
- 它必须接受一个
-
示例:
// 线程将要执行的函数 void* my_function(void* arg) { // 线程的具体逻辑... return NULL; // 必须返回一个 void* 类型的值 } // 在主线程中调用 pthread_create(&my_thread_id, NULL, my_function, NULL);
参数 4: void *arg
-
类型: 指向
void的指针 (void *)。 -
作用: 这是传递给线程入口函数(
start_routine)的参数。 -
如何传递多个参数?
void *只能传递一个指针,如果你想传递多个参数,你需要将它们打包到一个结构体中,然后将这个结构体的地址作为arg传递,在线程函数内部,再将这个指针强制转换回结构体指针,然后从中取出各个成员。
(图片来源网络,侵删) -
NULL: 如果你不需要给线程函数传递任何参数,可以直接传入NULL。 -
示例:
// 定义一个结构体来打包多个参数 struct my_args { int id; char *message; }; void* my_function(void* args) { struct my_args *real_args = (struct my_args *)args; printf("Thread ID: %d, Message: %s\n", real_args->id, real_args->message); free(real_args); // 记得释放动态分配的内存! return NULL; } int main() { pthread_t my_thread; struct my_args *args = malloc(sizeof(struct my_args)); args->id = 1; args->message = "Hello from thread!"; pthread_create(&my_thread, NULL, my_function, (void*)args); // ... 其他代码 ... pthread_join(my_thread, NULL); // 等待线程结束 return 0; }
返回值
- 成功: 返回
0。 - 失败: 返回一个非零的错误码,你可以使用
perror函数或strerror函数来打印出具体的错误信息。 - 示例:
if (pthread_create(&my_thread, NULL, my_function, NULL) != 0) { perror("Failed to create thread"); return 1; // 返回错误码 }
一个完整的、可运行的示例
下面是一个完整的 C 程序,它创建一个新线程,主线程和新线程分别打印自己的信息,并且主线程等待新线程结束后才退出。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h> // 用于 sleep 函数
// 线程的入口函数
void* thread_function(void* arg) {
int thread_num = *((int*)arg); // 将 void* 参数转换回 int*
printf("Hello from thread number %d! (PID: %d, TID: %lu)\n", thread_num, getpid(), pthread_self());
// 模拟一些工作
sleep(2);
printf("Thread number %d is finished.\n", thread_num);
free(arg); // 释放为参数分配的内存
return NULL; // 线程函数必须返回一个 void*
}
int main() {
pthread_t my_thread;
int thread_arg = 42; // 要传递给线程的参数
printf("Main thread (PID: %d, TID: %lu) is creating a new thread...\n", getpid(), pthread_self());
// 创建线程
// 将 thread_arg 的地址作为参数传递
if (pthread_create(&my_thread, NULL, thread_function, &thread_arg) != 0) {
perror("Error creating thread");
exit(EXIT_FAILURE);
}
printf("Main thread has created the new thread. The new thread's ID is %lu.\n", my_thread);
// 等待新线程执行完毕
// 如果没有这一行,主线程可能会在新线程开始前就退出了
pthread_join(my_thread, NULL);
printf("Main thread is finished.\n");
return 0;
}
如何编译和运行?
因为使用了 Pthreads 库,你需要使用 -lpthread 选项来链接它。
# 编译 gcc my_program.c -o my_program -lpthread # 运行 ./my_program
预期输出:
Main thread (PID: 12345, TID: 140123456789120) is creating a new thread...
Main thread has created the new thread. The new thread's ID is 140123455774848.
Hello from thread number 42! (PID: 12345, TID: 140123455774848)
Thread number 42 is finished.
Main thread is finished.
(注意:PID 和 TID 的值每次运行都会不同)
重要注意事项
- 链接 Pthreads 库: 在 Linux 或 macOS 上编译时,必须加上
-lpthread,在 Windows 上,如果你使用 MinGW 或 Cygwin,也需要这样做,Visual Studio 用户通常需要在项目设置中链接pthreadVC2.lib或类似的库。 - 线程同步: 当多个线程访问共享资源(如全局变量、静态变量)时,如果不加以控制,会导致竞态条件,你需要使用互斥锁 (
pthread_mutex_t)、条件变量 (pthread_cond_t) 等同步机制来确保数据的一致性。 - 内存管理: 通过
arg传递的指针指向的内存必须在被访问的线程函数中保持有效,通常的做法是在主线程中malloc内存,在线程函数中free它,如果传递的是栈上变量的地址,那是非常危险的,因为主线程可能会继续执行并覆盖掉栈上的数据。 - 线程终止:
- 线程函数执行到
return语句会正常退出。 - 调用
pthread_exit()函数可以主动退出线程。 - 一个线程可以被另一个线程通过
pthread_cancel()取消(不推荐,因为可能导致资源未释放)。
- 线程函数执行到
- 资源回收: 必须确保在线程结束后回收其资源,最常用的方法是使用
pthread_join(),它会让主线程阻塞,直到目标线程结束,如果你不关心线程何时结束,也可以调用pthread_detach()将线程设置为分离状态,这样线程结束后会自动回收资源,无需join。
