线程是一种轻量级的进程,一个进程至少包含 1 个线程,也可以包含多个线程,所有线程共享进程的资源,各个线程也可以拥有属于自己的私有资源。其实,进程仅负责为各个线程提供所需的资源,真正执行任务的是线程,而不是进程。
POSIX(可移植操作系统接口) 标准中规范了与多线程相关的系统接口。我们在 Linux 系统上编写多线程程序,只需在程序中引入
线程创建的过程,就是先调用pthread_create创建一个新线程,然后pthread_join,等待线程处理,最终就是终止线程。
我们先来学习一下几个关键的函数,man一下pthread_create这个函数,可以看到,这个函数有四个入参和一个返回int型返回值
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg);
参数1:放入一个线程标识符的地址
参数2:是对线程属性的修改,一般不修改,直接给null,pthread_create() 函数会采用系统默认的属性值创建线程。
参数3:以函数指针的方式指明新建线程需要执行的函数
参数4:线程处理函数的入参,要传入处理的参数,可以给null
返回值:创建成功则返回0,非0就表示不成功。
再man一下pthread_join这个函数,他是两个参数,返回值也是一个int型
int pthread_join(pthread_t thread, void **retval);
参数1:要等待的线程的线程标识符
参数2:保存线程处理函数的返回值,注意是二级指针
返回值: 返回0表示成功,非0表示不成功
pthread_join() 函数会一直阻塞调用它的线程,直至目标线程执行结束(接收到目标线程的返回值),阻塞状态才会解除。并且一个线程执行结束的返回值只能由一个 pthread_join() 函数获取,当有多个线程调用 pthread_join() 函数获取同一个线程的执行结果时,哪个线程最先执行pthread_join() 函数,执行结果就由那个线程获得,其它线程的 pthread_join() 函数都将执行失败。
此处给出一个示例代码,读者可以参考学习
- #include <stdio.h>
- #include <pthread.h>
-
- //定义线程要执行的函数,
- //arg为接收线程传递过来的数据
-
- void *Thread1(void *arg)
- {
- printf("hello world\n");
- return "thread1 finish";
- }
- void* Thread2(void* arg)
- {
- printf("hi world\n");
- return "thread2 finish";
- }
-
- int main()
- {
- int res; //存放创建是否成功的返回值
- pthread_t mythread1, mythread2; //定义两个线程的标识符
- void* thread_result; //定义一个void *的指针,后面可以给他赋任意类型的指针
- /*创建线程(create)
- &mythread:要创建的线程
- NULL:不修改新建线程的任何属性
- ThreadFun:新建线程要执行的任务
- NULL:不传递给 ThreadFun() 函数任何参数
-
- 返回值res为 0 表示线程创建成功,反之则创建失败。
- */
- res = pthread_create(&mythread1, NULL, Thread1, NULL);
- if (res != 0)
- {
- printf("线程创建失败\n");
- return -1;
- }
-
- res = pthread_create(&mythread2, NULL, Thread2, NULL);
- if (res != 0)
- {
- printf("线程创建失败\n");
- return -1;
- }
- /*
- 等待线程(join)
- mythread*:指定等待的线程
- &thead_result:接收 ThreadFun() 函数的返回值,或者接收 pthread_exit() 函数指定的值
-
- 返回值 res 为 0 表示函数执行成功,反之则执行失败。
- */
- res = pthread_join(mythread1, &thread_result);
- //输出线程执行完毕后返回的数据
- printf("%s\n", (char*)thread_result);
-
- res = pthread_join(mythread2, &thread_result);
- printf("%s\n", (char*)thread_result);
- printf("main thread finish\n");
- return 0;
- }
编译的时候需要加上-lpthread这个静态库,才能编译通过。(关于静态库和动态库的知识可以看我另一篇博文,链接如下)
编译的命令如下,可以看到运行的结果,没有问题。
有一个需要注意的点,上面这个程序,这个进程中,我们虽然自己只是创建了两个线程,但实际上是有三个线程,另外一个是本就存在的主线程,就像文章开头所说的,进程不办事,办事的都是线程,所以一个进程,最初肯定是有一个线程在的。
从程序中还可以看出的是, pthread_create() 函数成功创建的线程会自动执行指定的函数,不需要手动开启,此外,为了防止主线程提前退出,而没来得及执行其他线程,我们一般会在主线程中加上sleep延时一下。
终止线程执行的办法呢,有三种。
第一种自动终止,就是不去人为干预,线程运行完了自己就退出了,
第二种pthread_exit(),其实和return有点类似,但是pthread_exit()是专门用来退出一个线程的,不会影响其它线程的执行,而return是会影响到其他线程的,就比如在主线程中用了return,那整个程序就都退出了,包括其他的线程。使用的方法如下。
- void *ThreadFun(void *arg)
- {
- //终止线程的执行
- pthread_exit("线程终止成功"); //返回的字符串存储在常量区,并非当前线程的私有资源
- printf("线程终止失败");//此语句不会被线程执行
- }
第三种pthread_cancel()其实是一种信号终止,他具体是通过一个线程向另一个线程(需要在同一个进程内)发送终止信号来实现终止线程的,使用的方法就是在pthread_cancel()的括号中加上想要终止的线程标识符就行。
- int pthread_cancel(pthread_t thread);
- //返回值是0说明终止成功