Linux——多线程(一)

简介: Linux——多线程(一)

多线程

进程内进行资源划分

之前说过页表有用户级页表和内核级页表,现在再来扩展一下。

这里也能解释为什么对于常量字符串类型为什么不能修改了,因为要修改的时候会从虚拟地址转化成物理地址,然后检查权限是否可以修改等等。

如何看待地址空间和页表呢?

1.比如进程看到的堆区,栈区等等各种的资源窗口。

2.页表决定进程真正拥有资源的情况。(因为虚拟地址空间根本无法决定实际情况)

3.合理的对地址空间+页表进行资源划分,我们就可以对一个进程所有资源进行分类。(比如虚拟地址空间中的堆区,栈区,内核区,通过页表映射到不同的物理地址内存)

从虚拟地址到物理地址是怎么样通过页表访问的呢?

如果是32位地址的OS,就有232个地址,那么页表是不是就要有232个条目呢?一个条目算上物理地址,是否命中,读写权限等等就需要很多的内存,总共算下来需要的内存是非常庞大的,这样显然是不可能的。

其实物理内存早就被划分好了区域,每一块叫做数据页。(也叫做页框)

每一个页框也被管理:

struct Page
{
  //内存属性——4KB
}

然后通过struct Page类型的数组来管理。

并且磁盘中是数据也是被划分成4KB大小一块。

然后再说说虚拟地址空间的地址:32个比特位都有相对应的含义。

首先前十个对应的是页目录记录页表的地址,后面的10个是页表记录物理内存的地址,最后面的12个是物理内存起始地址中的偏移量。

页表当中储存的就是页框的起始地址,最后通过偏移量来确定在物理内存中的实际大小,212也正好就是4KB。

也就是说其实在查找的时候OS其实只会创建一个页目录和一个页表,其他暂时不用的页表就先不用,也就是说不需要多少内存。

什么是线程

之前对于进程的概念是内核数据结构+进程对应的代码和数据。

之前创建一个子进程室友自己的独立性的,如果今天创建多个进程,和第一个进程指向同一个PCB,看到是同一块虚拟地址空间,然后让每个这种“进程”执行虚拟地址空间中的部分代码,这些“进程”就叫做线程。

在Linux下,创建的线程其实就是PCB而已。

因为通过进行资源划分,单个“进程”的执行粒度一定比之前的进程更细。

CPU不会看是不是线程,只会去处理每个线程或者是进程。

OS也需要去管理这些线程。

专门管理线程的叫做TCB。

在windows操作系统就是这么设计的,CPU会先找到某个进程,然后进入这个进程中再去找线程。

(这样的设计是很复杂的,也不好维护)

从被执行的角度来看,进程和线程的区别并不是很大。

这就是为什么Linux中的线程只是复用PCB,用PCB来表示“线程”。

线程其实就是进程的一个执行流:

线程在进程的内部运行,线程在进程的地址空间内运行,拥有该进程的一部分资源。

也就是说:

这里整体才算是一个完整的进程。

内核视角:承担分配系统资源的基本实体。(创建进程所需要的各种资源)

如果按照概念来说,相对比之前说的进程只有一个执行流,现在的进程是拥有多个执行流。

在Linux中,什么是线程呢?是CPU调度的基本单位。

在Linux中,一个线程被称为轻量级进程。

总结:

1.Linux内核中没有真正意义上的线程,是用PCB来模拟线程的,是一种完全属于自己的一套线程方案。

2.站在CPU的角度,每一个PCB都可以被叫做轻量级进程

3.Linux线程是CPU调度的基本单位,而进程是承担分配系统资源的基本单位。

4.进程是整体申请资源,线程是向进程申请资源。

Linux线程的优点是什么呢?

比Windows操作系统的线程简单,维护成本低,可靠,高效。

线程的具体作用呢?

就像迅雷的边播放边下载。

Linux无法直接提供创建线程的系统调用,只能提供创建轻量级进程的接口。

进一步理解线程

先来用一份代码来看看线程:

pthread_create函数介绍

第一个参数是线程id,第二个参数是线程属性(大部分情况设置为nullptr),第三个参数是回调函数,让该线程执行这个函数。第四个参数是第三个参数的回调函数的参数。

成功返回0,失败返回错误码。

并且这个函数是第三方库的内容:pthread。

这是因为Linux没有真正意义上的线程。

#include <iostream>
#include <pthread.h>
#include <cassert>
#include <unistd.h>
using namespace std;
void *pthread_routine(void* args)
{
    while(true)
    {
        cout << "我是新线程" << endl;
        sleep(1);
    }
}
int main()
{
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, pthread_routine, (void *)"111111");//参数记得强制转换成void*
    assert(n == 0);
    (void)n;
    while(true)
    {
        cout << "我是主线程" << endl;
        sleep(1);
    }
    return 0;
}

任何Linux操作系统都必须默认携带这个库,这个库叫做原生线程库。

运行的时候发现只有一个进程。

终止之后就没有了。

然后用ps -al查看轻量级进程。

这里有两个执行流,PID相同,说明属于同一个进程,旁边的LWP不同,这个就是轻量级进程的id。

两个id相同的是主线程,不同的是新线程。

这里也说明CPU进行调度的时候是以LWP为标准特定执行流的。

并且,主线程还可以给新线程发送内容:

#include <iostream>
#include <pthread.h>
#include <cassert>
#include <unistd.h>
using namespace std;
void *pthread_routine(void* args)
{
    const char* p = (const char*)args;
    while(true)
    {
        cout << "我是新线程" << p << endl;
        sleep(1);
    }
}
int main()
{
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, pthread_routine, (void *)"111111");//参数记得强制转换成void*
    assert(n == 0);
    (void)n;
    while(true)
    {
        cout << "我是主线程,新线程id是:" << tid << endl;//这里顺便打印新线程的id
        sleep(1);
    }
    return 0;
}

相关文章
|
7月前
|
消息中间件 存储 缓存
【嵌入式软件工程师面经】Linux系统编程(线程进程)
【嵌入式软件工程师面经】Linux系统编程(线程进程)
136 1
|
5月前
|
算法 Unix Linux
linux线程调度策略
linux线程调度策略
105 0
|
3月前
|
资源调度 Linux 调度
Linux C/C++之线程基础
这篇文章详细介绍了Linux下C/C++线程的基本概念、创建和管理线程的方法,以及线程同步的各种机制,并通过实例代码展示了线程同步技术的应用。
40 0
Linux C/C++之线程基础
|
3月前
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解
|
5月前
|
存储 设计模式 NoSQL
Linux线程详解
Linux线程详解
|
5月前
|
缓存 Linux C语言
Linux线程是如何创建的
【8月更文挑战第5天】线程不是一个完全由内核实现的机制,它是由内核态和用户态合作完成的。
|
5月前
|
负载均衡 Linux 调度
在Linux中,进程和线程有何作用?
在Linux中,进程和线程有何作用?
|
5月前
|
缓存 Linux C语言
Linux中线程是如何创建的
【8月更文挑战第15天】线程并非纯内核机制,由内核态与用户态共同实现。
|
7月前
|
API
linux---线程互斥锁总结及代码实现
linux---线程互斥锁总结及代码实现
|
7月前
|
Linux API
Linux线程总结---线程的创建、退出、取消、回收、分离属性
Linux线程总结---线程的创建、退出、取消、回收、分离属性

热门文章

最新文章