1、线程的概念:
线程是进程内部的一条执行序列(执行流),每个进程至少有一条执行序列,即每个进程
至少有一个线程。进程可以通过线程库创建N个线程,这些新创建的线程称之为函数线程,main函数代表的线程为主线程。
2、线程与进程的区别:
(1) 进程是资源分配的最小单位,线程是CPU 调度的最小单位;
(2) 线程是轻量级的进程;
(3) 两者的管理方式不同,进程由PCB(进程控制块)管理,线程由线程结构管理;
(4) 线程有用户态和内核态的实现方式的选择(下面会详细介绍两种方式),因为线程
是进程内部的东西,存在由进程直接管理线程的可能性;而进程就没有实现方式的
问题,因为进程是在CPU上实现并发,而CPU由操作系统管理,因此进程的实现只能
由操作系统来完成。
3、线程的优缺点
优点:
(1) 可以将一个复杂的应用程序分解成几个线程来执行,从而改善程序的性能,并且
有时会让程序看起来好像在同时做两件事,比如说,在编辑文档的同时对文档中
的单词个数进行实时统计,简单的来说就是一个线程负责处理用户的输入并执行
文本编辑工作,另一个线程则不断刷新单词计数变量,第一个线程通过共享这个
计数变量让用户了解自己的工作进度。
(2) 线程之间的切换需要操作系统做的工作要比进程之间的切换少得多,因此多个线程
需要的资源要远小于多个进程。
缺点:
(1) 线程之间的交互非常难控制,因此多线程程序的调试会比较难;
(2) 多处理线程的程序需要拥有多个处理器核来支持,如果放在一台单处理器上
并不一定会运行的更快。
4、线程实现的三种方式
(1) 内核态:
由操作系统来管理线程,即将线程控制块放到操作系统内核空间,这样做的
好处有用户可以编程保持简单,用户程序员不需要管理线程的调度,这些都有
操作系统来监控;当然也有坏处,首先线程每次切换都要陷入内核由操作系统
来完成,造成效率较低,其次如果内核空间满了的话将无法成功创建线程。
(2) 用户态:
由进程自己来管理线程,即由用户自己来完成线程的切换及信息管理,操作系
统不需要知道线程的存在,但需要用户自己写一个执行系统作调度器,这也是一个
线程,所以没有能力强行夺走控制权去中断一个正在执行的线程,这会造成一个线
程阻塞则这个进程也被阻塞,同时编程也会比较复杂;优点是灵活性强,线程切换
快。
(3) 混合模式:
中和内核态和用户态的缺陷,结合二者有了混合模式。在分配线程时,将需要
执行阻塞操作的线程设为内核态线程,而将不会执行阻塞操作的线程设为用户态线
程。用户态的执行系统负责进程内部线程在非阻塞时的切换,内核态的操作系统负
责阻塞线程的切换,即同时实现内核态和用户态线程管理。每个内核态线程可以服务
一个或多个用户态线程。
5、线程的创建
#include<pthread.h>
int pthread_create(pthread_t *id,pthread_attr_t *attr,
void*(*fun)(void),void* arg);
id:函数成功返回时,id指向创建新线程的线程ID;
attr:定制不同的线程属性,一般设置为NULL;
fun:返回值为void*的函数指针,这里不是函数调用,而是创建函数线程;
arg:如果向fun函数传递的参数不止一个,将这些参数放到一个结构体,arg则指向这个
结构体的地址;
注意:
(1) 包含线程创建函数的源代码要想生成可执行文件,在编译时必须链接动态库:
gcc -o pthread pthread.c -lpthread
(2) 创建出来的函数进程不同于函数调用,函数调用是这条执行流的一部分,函数线程
是创建出一条独立的执行序列,它与主线程同时执行,并且与主线程的pid相同;
(3) 主线程与函数线程的区别:主线程是进程的切入点;
(4) 线程结束不以exit(0)结束,以int pthread_exit(void*)结束,参数可以设置为线程结束
状态;函数线程创建后与主线程同时执行,主线程以pthread_exit函数结束,即进程结
束,所有的函数线程都将结束;
(5) 等待线程结束可以用:
int pthread_join(pthread_t id,void*);
可以获取到等待的线程通过pthread_exit函数设置的结束状态信息。
练习:创建函数线程,主线程完成对数组元素的排序,函数线程完成简单的打印.
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<pthread.h>
void* pthread_fun()
{
int i;
for(i=0;i<5;i++)
{
printf("hello\n");
}
pthread_exit("world\n");
}
int main()
{
pthread_t id;
int res = pthread_create(&id,NULL,pthread_fun,NULL);
assert(res == 0);
int arr[6] = {2,5,3,7,9,8};
int i;
int j;
int tmp ;
for(i=0;i<6;i++)
{
for(j=i;j<6;j++)
{
if(arr[i]>arr[j])
{
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
}
for(i=0;i<6;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
pthread_exit("over\n");
return 0;
}