线程的基本概念
线程是进程内部的一条执行序列。进程内部至少有一条执行线程,即就是main函数的执行体。进程内部可以有多条线程,main函数的线程称为主线程,包括其执行过程中调用的其他的函数,而其他线程称为函数线程,函数线程是由主线程通过系统调用函数创建的。
线程与进程的区别
1、进程是资源分配的最小单位,线程是系统调度(执行)的最小单位。
2、线程切换比进程切换消耗小。
3 、进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮。
线程的分类
1、用户级:在用户空间是多线程的,内核只识别进程整体。线程创建、管理、销毁都是由用户空间负责,用户通过调用库函数来完成。用户态和内核态是n:1的关系。
2、内核级:线程的创建、控制、销毁都是由内核实现的,每个线程对内核都是可见的。用户态和内核态是n:n的关系。
3、组合模型:一部分是用户级,一部分是内核级。介于内核级和用户级之间,用户态创建多个线程,内核看到的也是多个,是n:m的对应关系。
线程的使用
1、线程的创建
头文件:#include<pthread.h>
库函数:
int pthread_create(pthread_t *id,pthread_attr_t *attr,void *(*pthread_fun)(void *),void *arg);
id:线程的编号,有系统自动填充;
attr:线程属性;
pthread_fun:线程创建以后所调用的函数地址
arg:传递给函数线程的参数。
总结:
(1)pthread_create函数是库函数,编译的时候必须加载其动态库libpthread.so。
(2)线程函数和写一个普通函数没有明显差别,只不过在主线程不会调用线程函数,而是在创建线程的时候指定函数线程执行的代码入口地址(即就是函数的入口地址)。称主函数为主执行序列,函数的执行为函数线程的执行流。
(3)主线程和函数线程同时执行,一个进程同时执行多个任务。
2、 线程的结束
exit是结束进程的函数,主线程要结束但是函数线程还在运行,我们主线程就不能调用exit结束,必须使用pthread_exit(void *reval);
线程等待其他线程结束
int pthread_join(pthread_t id,void **p);
作用:获取指定线程有由pthread_exit设置的退出信息。
特性:pthread_join函数会阻塞直到等待的线程退出(类比进程控制中的wait函数)。
3、线程间数据共享
(1)全局变量 共享
(2)局部变量(栈区) 不共享
(3)堆区 共享
(4)文件 共享 同一个进程的线程,使用一个PCB,只要线程能线程能拿到打开文件的文件描述符,就可以通过文件描述符操作文件。
4、代码举例
头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
例1:pthread1.c
void * fun_pthread1(void *arg)
{
sleep(1);
pthread_t pid = *(pthread_t *)arg;//获取线程2的id
pthread_join(pid,NULL);//等待线程2结束
int i,j;
for(i=2;i<=100;i++)//打印100以内的素数
{
int count = 0;
for(j=1;j<=100;j++)
{
if(i%j==0)
{
count++;
}
}
if(count == 2)
{
printf("%d ",i);
}
}
printf("\n");
}
void * fun_pthread2(void *arg)//对数组元素进行排序,并打印结果
{
int arr[] = {18,23,9,56,90,76,81,44,38,62};
int len = sizeof(arr)/sizeof(arr[0]);
int i,j;
for(i=0;i<len-1;i++)
{
int min_index = i;
for(j=i+1;j<len;j++)
{
if(arr[j] < arr[min_index])
{
min_index = j;
}
}
int temp = arr[min_index];
arr[min_index] = arr[i];
arr[i] = temp;
}
for(i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
pthread_exit("sort over");
}
int main()
{
printf("Main Thread run\n");
pthread_t id1,id2;
pthread_create(&id1,NULL,fun_pthread1,(void *)&id2);//传递另一个线程的id
pthread_create(&id2,NULL,fun_pthread2,NULL);
int *p;
pthread_join(id1,NULL);//等待线程1结束
// pthread_join(id2,(void **)&p);//等待线程2结束,并获取线程退出时携带的数据
// printf("%s\n",p);//打印线程2退出时携带的数据
sleep(5);
return 0;
}
运行结果
例2:pthread2.c
//函数线程
void * fun(void *arg)
{
printf("Child Thread Run\n");
int j;
for(j=0;j<5;j++)
{
printf("child:j = %d\n",j);
sleep(2);
}
//打印主线程传递的参数
printf("a = %d\n",*(int *)arg);
}
int main()
{
printf("Main Thread Run\n");
pthread_t id;
int a = 10;
int val = pthread_create(&id,NULL,fun,(void *)&a);
assert(val == 0);//若创建线程成功,则返回0
a = 20;
int i;
for(i=0;i<3;i++)
{
printf("main:i = %d\n",i);
sleep(1);
}
pthread_exit(NULL);//线程结束
return 0;
}
运行结果