线程的引入:
在之前提及到进程的概念包含两个特点:
1、资源所有权:每个进程都有自己独立虚拟的地址空间(在Linux下即为一个mm_struct的结构体)。这同时也代表了进程是独占资源的:(这些资源包含内存,I/O通道,I/O设备和文件),操作系统执行保护功能以防止进城之间发生不必要的与资源相关的冲突。
2、调度/执行
一个进程是否被调度,是有调度器决定的,进程是调度的基本单位。
这两个特点都是独立的,那么操作系统应该能够独立的处理。为了区分这两个特点,操作系统是将资源直接分配给进程,因此进程是拥有资源所有权的单位,而此时调度的基本单位就变成了线程,或者轻量级线程。
因此此时的进程较为之前所提到的进程更加精细。它只是承担了资源的分配,并不再是调度的基本单位。
一个进程可以有一个线程即为单线程
一个进程也可以有多个线程即单进程多线程(这多个线程是这个进程的执行分支)。
多进程,每个进程可以有一个线程
多进程,每个进程可以有多个线程。·
线程的实现可以分为用户级线程和内核级线程(内核级线程又称作内核支持的线程或轻量级进程)
1、用户级线程又优点也有缺点。
用户级线程的切换不需要内核态特权,因此省去了两次状态转换的开销。这个优点也是它的缺点,由于内核是看不到这个用户级线程的,因此在使用系统调用接口的时候就会发生阻塞,并且一旦阻塞,这个进程内的所有线程都会被阻塞。
2、轻量级进程
轻量级进程可以看做是用户级进程和内核级线程的映射。它在发生阻塞的时候不会让整个进程都阻塞。
3、内核级进程
这是可以 进行调度的实体。它在发生阻塞的时候不会让整个进程都阻塞。
线程和进程的区别:
进程是操作系统分配资源的单位,线程是调度的基本单位。进程是独占资源的,而线程是可以共享进程的资源的。
在一个已有进程中创建一个线程比创建一个进程所需要的时间少的多。
终止一个线程比终止一个进程所需的时间少的多
同一个进程内线程的切换比进程间切换时间少得多
Linux下的线程
Liunx下是没有真正意义上的线程的,Linux提供一种不区分进程和线程的解决方案。因此Linux下的所谓的线程是通过进程模拟得到的,因此Linux下所谓的线程也是有它的PCB的,通过phread库组成用户级进程的多个用户级线程映射到共享同一组ID的多个Linux内核级的进程上。
总之Linux的线程还是进程,它也有自己的PCB,Linux下的线程是为了共享进程的资源的,
。由于同一进程的多个线程共享同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用。如果定义一 个全局变量,在各线程中都可以访问到。
除此之外,各线程还共享以下进程资源和环境:
1. ⽂文件描述符表
2. 每种信号的处理方式(SIG_IGN、SIG_DFL或者自定义的信号处理函数)
3.当前工作目录
4. ⽤用户id和组id
但有些资源是每个线程各有⼀一份的:
1. 线程id
2、上下文,包括各种寄存器的值、程序计数器和栈指针 //很重要,比如在发生线程切换的时候一定要保存上下文信息
3. 栈空间//因为线程是独立执行的,而函数参数,局部变量都保存在栈中,他在执行的时候要从栈中拿数据,因此为了保证线程间不互相干扰,因此它的堆栈必须是独立的。因此也很重要。
4. errno变量
5.信号屏蔽字
6. 调度优先级
线程的创建:
#include<stdio.h>
#include <pthread.h>
#include<stdlib.h>
void* pthread(void*buf)
{
printf("%s,pid is :%d,tid is :%u\n",(char*)buf,getpid(),pthread_self());
}
int main()
{
pthread_t id1;
int ret= pthread_create(&id1,NULL,pthread,"this is pthread1");
if(ret!=0)
{
printf("create faild,%s",strerror(ret));
}
printf("main pthread:pid is :%d,tid is :%u\n",getpid(),pthread_self());
sleep(1);
return 0;
}
进程的等待:pthread_join是默认等待的是没有发生异常终止的线程
.终止线程 : 如果需要只终止某个线程而不终止整个进程,可以有三种方法:
1. 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit,整个进程都结束了。
2. 一个线程可以调用pthread_cancel终止同一进程中的另一个线程。如果thread线程被别的线程调⽤用pthread_cancel异常终掉,value_ptr所指向的单元⾥里存放 的是常数PTHREAD_CANCELED (-1),对于一个线程在合理的权限范围内是允许自己取消和被取消的。
3. 线程可以调用pthread_exit终止自己。
#include<stdio.h>
#include <pthread.h>
#include<stdlib.h>
void* pthread1(void*buf)
{
printf("%s,pid is :%d,tid is :%u\n",(char*)buf,getpid(),pthread_self());
return (void*)1;
}
void *pthread2(void*buf)
{
printf("%s,pid is :%d,tid is :%u\n",(char*)buf,getpid(),pthread_self());
pthread_exit((void*)2);
}
int main()
{
pthread_t id1;
pthread_t id2;
void *code1;
int ret= pthread_create(&id1,NULL,pthread1,"this is pthread1");
if(ret!=0)
{
printf("create thread1 faild,%s",strerror(ret));
}
sleep(1);
pthread_join(id1,&code1);
printf("main pthread:pid is :%d,tid is :%u,code1 is:%d\n",getpid(),pthread_self(),(int)code1);
sleep(1);
void*code2;
int err= pthread_create(&id2,NULL,pthread2,"this is pthread2");
if(err!=0)
{
printf("create thread1 faild,%s\n",strerror(err));
}
pthread_cancel(id2);
pthread_join(id2,&code2);
printf("main pthread:pid is :%d,tid is :%u,exit code is%d\n",getpid(),pthread_self(),(int)code2);
return 0;
}
在任何一个时间点上,线程是可结合的(joinable)或者是分离的(detached)
一个可 结合的线程能够被其他线程收回其资源和杀死。在被其他线程回收之前,它的存储器资源 (例如栈)是不释放的。相反,⼀一个分离的线程是不能被其他线程回收或杀死的,它的存 储器 资源在它终⽌止时由系统⾃自动释放。
一个线程可以自行分离,也可以被被分离,分离之后它的资源由操作系统来自动释放,因此主线程不会因为它还没运行结束处于阻塞状态。
#include <pthread.h>
# int pthread_detach(pthread_t thread);
RETURN VALUE
On success, pthread_detach() returns 0; on error, it returns an error number.
分离之后如果再去等待则会等待失败
自己分离自己
void* pthread1(void*buf)
{
int err= pthread_detach(pthread_self());
if(err==0)
{
printf("detach sucessful!\n");
}
else
{
printf("detach failure\n");
}
printf("%s,pid is :%d,tid is :%u\n",(char*)buf,getpid(),pthread_self());
return (void*)1;
}
在主线程里使线程1被分离
int main()
{
pthread_t id1;
pthread_t id2;
void *code1;
int ret= pthread_create(&id1,NULL,pthread1,"this is pthread1");
pthread_detach(id1);
if(ret!=0)
{
printf("create thread1 faild,%s",strerror(ret));
}
sleep(1);
int join=pthread_join(id1,NULL);
if(join!=0)
{
printf("pthread_join faild\n");
}
printf("main pthread:pid is :%d,tid is :%u,code1 is:%d\n",getpid(),pthread_self(),(int)code1);
sleep(1);
void*code2;
int err= pthread_create(&id2,NULL,pthread2,"this is pthread2");
if(err!=0)
{
printf("create thread1 faild,%s\n",strerror(err));
}
pthread_cancel(id2);
pthread_join(id2,&code2);
printf("main pthread:pid is :%d,tid is :%u,exit code is%d\n",getpid(),pthread_self(),(int)code2);
return 0;
}