一、线程的三个重要的应用程序接口(API)
1.1 线程的创建
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
当pthread_create成功返回0。
- 由
tidp
指向的内存单元被设置为新创建线程的线程ID。 attr
参数用于定制各种不同的线程属性,暂可以把它设置为NULL
,以创建默认属性的线程。(工作中也多用NULL
)- 新创建的线程从
start_rtn
(函数指针)函数的地址开始运行,该函数只有一个无类型指针参数arg
。 - 如果需要向
start_rtn
函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg
参数传入。
1.2 线程的退出
单个线程可以通过以下三种方式退出,在不终止整个进程的情况下停止它的控制流:
- 线程只是从启动例程中返回,返回值是线程的退出码。
- 线程可以被同一进程中的其他线程取消。
- 线程调用pthread_exit:
#include <pthread.h>
int pthread_exit(void *rval_ptr);
rval_ptr 是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以通过调用 pthread_join 函数访问到这个指针。
1.3 线程的等待
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 返回:若成功返回0,否则返回错误编号
调用这个函数的线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。
- 如果例程只是从它的启动例程返回,rval_ptr 将包含返回码。
- 如果线程被取消,由 rval_ptr 指定的内存单元就置为PTHREAD_CANCELED。
可以通过调用pthread_join自动把线程置于分离状态,这样资源就可以恢复。如果线程已经处于分离状态,pthread_join 调用就会失败,返回 EINVAL。
如果对线程的返回值不感兴趣,可以把 rval_ptr 置为 NULL 。在这种情况下,调用 pthread_join 函数将等待指定的线程终止,但并不获得线程的终止状态。
在 Linux 的 C 语言多线程环境中,启动例程通常指的是主线程(Main Thread)中的入口函数。在多线程程序中,主线程是程序的起点,它负责创建和管理其他线程,并在程序执行完成后终止整个进程。
在 C 语言中,主线程的入口函数通常是
main
函数。main
函数是程序的入口点,当程序启动时,操作系统会调用main
函数作为程序的起点。在多线程程序中,主线程的main
函数会负责创建其他线程,分配资源,执行逻辑代码,并最终等待其他线程执行完成后终止整个进程。例程(routine)通常指的是一段执行特定任务的代码块或函数。在多线程环境中,每个线程都有自己的例程,用于定义线程要执行的任务。主线程的例程就是
main
函数,而其他线程的例程可以是通过线程创建函数(如pthread_create
)传入的函数指针,用于定义线程要执行的任务。总的来说,在 Linux 的 C 语言多线程环境中,启动例程指的是主线程的入口函数
main
,而例程指的是线程要执行的任务代码块或函数。主线程的main
函数负责创建其他线程,并启动线程执行各自的例程。
二、让线程返回int类型的值
#include <stdio.h>
#include <pthread.h>
void* fun1(void *arg)
{
//static(全局变量): 保证函数调用结束后,变量值还在
static int ret = 10;
printf("t1:%ld thread is create\n", (unsigned long)pthread_self());
printf("t1: %d\n", *((int*)arg));
// 3.退出线程函数
pthread_exit((void *)&ret);//pthread_join可以通过其第二个参数访问这个指针
}
int main()
{
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int ret;
int param = 100;
pthread_t t1;
int *pret = NULL;
//1.创建线程
// 线程属性 线程函数 线程函数参数
ret = pthread_create(&t1, NULL, fun1, (void*)¶m);
if(ret == 0){
printf("main:create t1 success\n");
} else {
perror("why t1 fail");
}
printf("main:%ld\n", (unsigned long)pthread_self());//打印主线程ID
//2.等待线程函数退出
pthread_join(t1, (void**)&pret);//等待线程结束,防止进程结束,线程还未执行完毕
//4.输出线程int返回值
printf("main: pret=%d\n", *pret);
return 0;
}
二、让线程返回字符串(char*)类型的值
//demo3
#include <stdio.h>
#include <pthread.h>
void* fun1(void *arg)
{
static char* p = "t1 run out";//static(全局变量): 保证函数调用结束后,变量值还在
printf("t1:%ld thread is create\n", (unsigned long)pthread_self());
printf("t1: %d\n", *((int*)arg));
//3.退出线程函数 返回返回值
pthread_exit((void *)p);//pthread_join可以通过其第二个参数访问这个指针
}
int main()
{
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int ret;
int param = 100;
pthread_t t1;
char *pret = NULL;
//1.创建线程
// 线程属性 线程函数 线程函数参数
ret = pthread_create(&t1, NULL, fun1, (void*)¶m);
if(ret == 0){
printf("main:create t1 success\n");
} else {
perror("why t1 fail");
}
printf("main:%ld\n", (unsigned long)pthread_self());//打印主线程ID
//2.等待线程
pthread_join(t1, (void**)&pret);//等待线程结束,防止进程结束,线程还未执行完毕
//4.输出线程字符串返回值
printf("main: pret=%s\n", pret);
return 0;
}