前几天心血来潮,想用C语言复现一下“睡眠排序”,进而了解了C语言中多线程的使用方法,记录如下:
预备知识
进程和线程
进程是对运行时程序的封装,是系统进行资源调度和分配的的基本单位,实现了操作系统的并发。
线程是进程的子任务,是CPU调度和分派的基本单位,用于保证程序的实时性,实现进程内部的并发。
两者的区别
一个线程只能属于一个进程,而一个进程可以有多个线程。线程依赖于进程存在。
进程在执行过程中拥有独立的内存单元,而多个线程共享进程的内存。
C语言中使用多线程
在C语言中使用多线程,需要用到头文件 pthred.h
多线程涉及的几个函数:
-
创建线程 pthread_create()
函数原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
参数解释如下:
- *pthread_t thread:传递一个 pthread_t 类型的指针变量,也可以直接传递某个 pthread_t 类型变量的地址。pthread_t 是一种用于表示线程的数据类型,每一个 pthread_t 类型的变量都可以表示一个线程。
- *const pthread_attr_t attr:用于手动设置新建线程的属性,例如线程的调用策略、线程所能使用的栈内存的大小等。大部分场景中,我们都不需要手动修改线程的属性,将 attr 参数赋值为 NULL,pthread_create() 函数会采用系统默认的属性值创建线程。
- void *(*start_routine) (void *):以函数指针的方式指明新建线程需要执行的函数,该函数的参数最多有 1 个(可以省略不写),形参和返回值的类型都必须为 void* 类型。void* 类型又称空指针类型,表明指针所指数据的类型是未知的。使用此类型指针时,我们通常需要先对其进行强制类型转换,然后才能正常访问指针指向的数据。
- *void arg:指定传递给 start_routine 函数的实参,当不需要传递数据时,将 arg 赋值为 NULL 即可。
-
结束线程 pthread_exit()
函数原型
pthread_exit(void *retval)
参数解释如下:
- retval 是 void* 类型的指针,可以指向任何类型的数据,它指向的数据将作为线程退出时的返回值。如果线程不需要返回任何数据,将 retval 参数置为 NULL 即可。
注意:retval 指针不能指向函数内部的局部数据(比如局部变量)。换句话说,pthread_exit() 函数不能返回一个指向局部数据的指针,否则很可能使程序运行结果出错甚至崩溃。
-
等待线程 pthread_join()
函数原型
pthread_join(pthread_t thread, void **retval)
参数解释如下:
- thread 参数用于指定接收哪个线程的返回值。
- retval 参数表示接收到的返回值,如果 thread 线程没有返回值,或者我们不需要接收 thread 线程的返回值,可以将 retval 参数置为 NULL。
pthread_join() 函数会一直阻塞调用它的线程,直至目标线程执行结束(接收到目标线程的返回值),阻塞状态才会解除。
利用多线程实现“睡眠排序”
源代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> //多线程头文件
#include <unistd.h> //包含延时函数的头文件
void *sleep_sort(void *args) {
int *tmp = (int *)args;
sleep(*tmp);
printf("%d ", *tmp);
}
int main() {
int max;
printf("请输入要排序几个数:");
scanf("%d", &max);
int num[max];
printf("请输入要排序的%d个数:\n", max);
for(int i = 0; i < max; i++) {
scanf("%d", &num[i]);
}
printf("开始对");
for(int i = 0; i < max; i++) {
printf("%d ", num[i]);
}
printf("进行排序:\n");
pthread_t th[max]; //创建线程数组并为每个线程传入参数
for(int i = 0; i < max; i++) {
pthread_create(&th[i], NULL, (void *)sleep_sort, &num[i]);
}
for(int i = 0; i < max; i++) {
pthread_join(th[i], NULL); //为每个线程设置等待
}
printf("\n");
}
测试运行: