什么是线程?
线程是进程中的单个序列流。因为线程具有进程的一些属性,所以它们有时被称为轻量级进程。
进程和线程有什么区别?
线程并不独立于其他类似的进程,因此线程与其他线程共享其代码段、数据段和操作系统资源,如打开的文件和信号。但是,与进程一样,线程也有自己的程序计数器(PC)、寄存器集和堆栈空间。
为什么选择多线程?
线程是并行运行的,可以提高应用程序效率。例如,在浏览器中,多个选项卡可以是不同的线程。MS Word使用多个线程,一个线程来格式化文本,另一个线程来处理输入等等。
线程的运行速度比进程快,原因如下:
- 线程创建速度快得多
- 线程之间的上下文切换要快得多
- 线程可以轻松终止
- 线程之间的通信更快
查看 更多信息
我们可以用C写多线程程序吗?
与Java不同,C语言标准不支持多线程。POSIX线程(或Pthread)是线程的POSIX标准。pthread的实现可通过GCC编译器获得。
例子1
请注意:下面的程序只能用带有pthread库的C编译器编译
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // multithread.c -- 演示pthread基本函数用法的简单C程序 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> // 作为线程执行的普通C函数 void *myThreadFun(void *vargp) { sleep(1); printf("来自线程的消息 "); return NULL; } int main() { pthread_t thread_id; printf("线程之前 "); pthread_create(&thread_id, NULL, myThreadFun, NULL); pthread_join(thread_id, NULL); printf("线程之后 "); exit(0); } |
要编译程序,需要链接到 pthread 库,所以编译命令如下
1 | gcc multithread.c -lpthread |
输出结果
1 2 3 | 线程之前 来自线程的消息 线程之后 |
在main()中,我们声明了一个名为thread_id的变量,其类型为pthread_t,这是一个用于标识系统中线程的整数
在声明thread_id之后,我们调用pthread_create()函数来创建线程
- 第一个参数是指向由该函数设置的thread_id的指针
- 第二个参数指定属性。如果值为NULL,则应使用默认属性
- 第三个参数是要为要创建的线程执行的函数的名称
- 第四个参数用于将参数传递给函数myThreadFun
- 线程的pthread_join()函数相当于进程的wait()。对 pthread_join 的调用将阻塞调用线程,直到标识符等于第一个参数的线程终止
例子2
如上所述,所有线程共享数据段。全局变量和静态变量存储在数据段中。因此,它们由所有线程共享。下面的示例程序演示了相同的情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | // 显示具有全局变量和静态变量的多线程的C程序。 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> // 创建一个全局变量来在线程中更改它 int g = 0; // 这个函数将被所有线程执行 void *myThreadFun(void *vargp) { // 存储传递给此线程的value参数 int *myid = (int *)vargp; // 创建一个静态变量来观察它的变化 static int s = 0; // 更改静态和全局变量 ++s; ++g; // 打印参数、静态变量和全局变量 printf("Thread ID: %d, Static: %d, Global: %d ", *myid, s, g); } int main() { int i; pthread_t tid; // 创建三个线程,使用同一个线程函数 for (i = 0; i < 3; i++) pthread_create(&tid, NULL, myThreadFun, (void *)&tid); pthread_exit(NULL); return 0; } |
输出结果
1 2 3 | Thread ID: -1164859648, Static: 1, Global: 1 Thread ID: -1173252352, Static: 2, Global: 2 Thread ID: -1173252352, Static: 3, Global: 3 |
可以看到,各个线程共享了主进程的全局变量和静态变量
请注意: 上面的例子来只是用于展示线程是如何工作的。在线程中的访问全局变量通常不是一个好主意。如果线程2的优先级高于线程1,而线程1需要更改变量,该怎么办?在实践中,如果需要由多个线程访问同一个全局变量,那么应该使用互斥来访问它们。
更多的例子 :pthread_cancel()、pthread_self() 函数