0x07 操作系统的线程知识

线程引入原因

  1. 性能
    操作系统开销大;
    Unix的轻型进程(fork)

  2. 应用
    进程代码并发执行的需求;
    例子:PPT编辑(输入/拼写检查/存盘)

  3. 硬件
    多核处理器;
    加速进程的运行

线程

线程

  • 可在CPU上运行的基本执行单位
  • 进程内的一个代码片段可以被创建称为一个线程
  • 线程状态:就绪、运行、等待等
  • 线程操作:创建、撤销、等待、唤醒等
  • 进程依旧是资源分配的基本单位
  • 线程自己不拥有系统资源,通过进程申请资源

传统进程

  • 重型进程
  • 只有一个线程:主线程
  • 单线程模型

进程和线程

方面 进程 线程
代码 进程包含线程 线程是进程中的一段代码
资源 进程是资源分配基本单位 线程不拥有资源,共享使用进程的资源
调度 同一进程中的线程切换不会引起进程切换 线程是基本调度单位
切换 重量级上下文切换,代价大 轻量级切换,代价小
生命期 进程撤销会导致它的所有线程被撤销 线程撤销不会影响进程

线程结构

  • 代码和数据:来自进程
  • 各类资源:来自进程
  • 线程控制块(TCB)
    包含线程ID,程序计数器PC,寄存器集,栈空间
    在这里插入图片描述
    Windows线程:
    在这里插入图片描述

单线程和多线程

单线程:
一个进程只有一个线程;
早期操作系统

多线程:
一个进程有多个线程;
支持线程的操作系统
在这里插入图片描述

线程优点

  1. 响应度高
    线程创建开销小;
    例子:web服务器
  2. 资源共享
    进程中的线程可以共享进程资源
  3. 经济性
    线程创建、上下文切换比进程快;
    Solaris:创建线程比进程快30倍,线程切换比进程切换快5倍
  4. MP体系结构的运用
    一个进程中的线程在不同处理器上并行运行

Web服务器

在这里插入图片描述

Windows线程

  1. 操作系统支持线程
  2. 线程主要数据结构:
    (1)执行线程块ETHREAD
    Executive thread block
    对应程序地址
    指向KTHREAD指针
    内核空间
    (2)核心线程块KTHREAD
    Kernel thread block
    线程调度和同步信息
    内核空间
    (3)线程环境块TEB
    Thread environment block
    用户空间的数据结构,线程本地存储

Linux 线程

  • Linux 2.2版引入线程
  • 通过clone() 系统调用创建线程
    类似fork
    Linux只支持克隆线程
  • 用术语“任务”表示进程和线程,一般不用“线程”
  • 用户线程:PThreads

Clone

  • 创建进程或者线程
  • Clone可有选择继承父进程的资源
    不和父进程共享
    int clone(int (\*fn)(void *),void *child_stack, int flags, void *arg)
    fn:函数指针,指向一个函数体,即想要创建进程的静态程序
    child_stack:给子进程分配系统堆栈的指针
    flags:要复制资源的标志,描述从父进程继承的资源

多线程模型

用户(管理)线程

用户线程:由用户线程库进行管理的线程

  • 内核看不到用户线程
  • 用户线程的创建和调度在用户空间内,不需要内核的干预
  • 应用于传统的只支持进程的操作系统

例子:

  • POSIX Pthreads
  • Win32 threads
  • Java threads

内核(管理)线程

内核线程:内核进行管理的线程

  • 需要内核支持
  • 由内核完成线程调度
  • 由内核进行创建和撤销

例子:Windows XP/2000,Solaris,Linux,Tru64 UNIX,Mac OS X

多线程模型

在这里插入图片描述

多对一模型

不支持内核线程的操作系统

  • 内核只有进程

内核只看到一个进程

  • 多个线程不能并行运行在多个处理器上

进程中的用户线程由进程自己管理

  • 进程内线程切换不会导致进程切换
  • 一个线程的系统调用会导致整个进程阻塞

在这里插入图片描述
例子:

  • Solaris Green Threads
  • GNU Portable Threads

一对一模型

用于支持线程的操作系统

  • 用户线程映射到内核线程
  • 操作系统管理这些线程

并发性好:多个线程可并行运行在多个处理器上

内核开销大

在这里插入图片描述
例子:
Windows
OS/2

多对多模型

多个用户线程映射为相等或更小数目的内核线程

  • 并发性和效率兼顾
  • 增加复杂度

在这里插入图片描述
例子:Solaris 9 以前的版本

Solaris 2 多对多模型
在这里插入图片描述

两级模型

类似于M:M

例子:IRIX,HP-UX,Tru64 UNIX,Solaris 8及早期版本


线程库

线程库

为程序员提供API来创建和管理线程

两种模式:
(1)用户库(用户线程)

  • 存在于用户空间
  • 没有内核支持
  • 调用线程库不会产生系统调用

(2)内核库(内核线程)

  • 存在于内核
  • 操作系统支持
  • 调用线程库会产生系统调用

Pthreads线程库

Pthreads:POSIX线程(POSIX threads)

  • 线程的POSIX标志
  • 定义了创建和操纵线程的一整套API
  • 用在类Unix操作系统(Unix、Linux、Mac OS X等)
  • Windows也有移植版pthreads-win32
  • 一般多为用户线程

POSIX标准:可移植操作系统接口(Portable Operating System Interface)

  • 定义了操作系统为应用程序提供的接口标准
  • 为各种UNIX软件定义的一系列API标准总称

常用线程操作

  • pthread_create():创建一个线程
  • pthread_exit():终止当前线程
  • pthread_cancel():中断另外一个线程的运行
  • pthread_join():阻塞当前的进程,直到另外一个线程运行结束
  • pthread_attr_init():初始化线程的属性
  • pthread_t:线程ID
  • pthread_attr_t:线程属性

Pthreads例子

gcc -o mypthread -lpthread mypthread.c

#include<stdio.h>
#include<pthread.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>

pthread_t ntid;

void *thr_fn(void *arg){
	printids("new thread:");
	return((void*)0);
}
int main(){
	int err;
	err=pthread_create(&ntid,NULL,thr_fn,NULL);
	if(err!=0){
		printf("can't create thread:%s\n",strerror(err));
		return 1;
	}
		sleep(1);
		return 0;
}

Java线程库

Java线程由JAVA虚拟机JVM管理

  • Java线程操作系统不可见
  • 用户线程
  • 定义了创建和操纵线程的一整套API
  • 跨操作系统平台

Java线程创建

  • 扩展java.lang,Thread类(书本例子)
  • 实现Runnable接口

Java线程例子

public class DoSomething implements Runnable{//Runnable接口
	private DoSomething(String name){
		this.name=name;
	}

	public void run(){//Run方法
		System.out.println(name+":"+i);
	}
}

public class TestRunnable{
	public static void main(String[] args){
		DoSomething ds1=new DoSomething("1"); 
		DoSomething ds2=new DoSomething("2"); 
		
		Thread t1 =new Thread(ds1); 
		Thread t2=new Thread(ds2); 
		
		t1. start();
		t2. start();
	}
}

java线程状态

在这里插入图片描述
在这里插入图片描述

win32线程库

  • win32线程库是内核库
  • 内核线程
  • 线程创建方法:Win32 API,MFC,.Net Framework
  • 线程创建:
    HANDLE CreateThread(LPSECURITY_ATTRIBUTES IpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE IpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD IpThreadld);
    线程函数原型:DWORD WINAPI threadfunc(LPVOID param);
  • 线程挂起:
    DWORD SuspendThread(HANDLE hThread);
  • 线程恢复:
    DWORD ResumeThread(HANDLE hThread);
  • 线程退出:
    VOID ExitThread(DWORD dwExitCode);
    BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);

win32线程例子

#include"stdafx.h"
#include <windows.h>
#include <iostream>
DWORD WINAPI Func(LPVOID param){
	while(true){ 
		Sleep(1000); 
		cout<<"hello!"; 
	}
	return 0; 
}
int main(int argc, char* argvI){
	int input=0; 
	HANDLE hand1=Create Thread(NULL,0, Func,(void*)& input, CREATE_SUSPENDED, NULL);
	while(true){
		cin>>input; 
		if(input==1){
			Resume Thread(hand1);
		}else if(input==2){
			Suspend Thread(hand1);
		}else{
			Terminate Thread(hand1,1); 
			return 0;
		}
	}
	return 0;
}

Windows线程状态

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ITmincherry/article/details/106153770
今日推荐