前言
本文将会向你介绍线程的概念,以及线程是怎么被创建的
线程概念
一、进程是承担系统资源的基本实体,线程是cpu调度的基本单位
首先,地址空间在逻辑上相当于进程的资源窗口, 每个进程都有这样一个资源窗口。通过地址空间+页表获取自身的代码和数据
那么有没有可能创建一个“进程”只需要创建一个pcb进程控制块即可?(以前创建进程,需要创建地址空间,页表,建立映射关系等等)
其实后续创建的每一个“进程”就是linux给出的线程的概念
每一个执行流占一份,每个执行流只需要占页表的一部分,就可以看到每一个区域不同的资源块
创建线程的量级明显比创建进程的要低, 创建进程要从0创建,pcb地址空间构建各种映射关系,页表,加载代码和数据,动态库也要加载,初始化各种代码和数据等等
创建线程只需要创建个pcb,并没有过多的资源申请,线程是参与资源分配的
LInux中线程的实现方案
操作系统只给线程是什么,特征是什么
具体一款os,无论底层怎么实现,只要符合给出的线程概念,就是线程,在教材里只给出线程的特征,但并不给出怎么实现线程,需要各个平台去实现符合概念的线程
(就好比不管你读的哪个大学,读的清华,还是北大,都是大学生)
综上所述:
1.线程创建更简单,
2.线程在进程的地址空间中运行(在进程内部中运行) 主进程创建时,申请地址空间,页表等等资源等到后续再创建线程时,就只需要创建一个pcb即可指向同一个地址空间,分配其中的资源,因此线程在进程的地址空间中运行
想必第一点你已经理解了,线程的创建更加地简单
那么第二点该如何理解呢?
从前的进程:内部只有一个执行流(红色框内的表示进程)
现在的进程(进程=内核数据结构+代码和数据):内部有多个执行流(整个红色框内表示一个进程)
其中第一个线程表示的是主线程
因此回到开头,进程(整个红色框所包含的)是承担系统资源的基本实体,而线程(一个个task_struct)是cpu调度的基本单位
往后cpu看到一个pcb就执行该pcb的方法,方法只需要能在地址空间上被分配资源,cpu就执行进程代码的一部分,访问进程数据的一部分
因此真实在cpu上真实跑的执行流(轻量级进程—线程)就比传统进程的量级要低一些
线程的创建
功能:创建一个新的线程
原型 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (start_routine)(void), void *arg);
参数:
thread:返回线程ID attr:设置线程的属性
attr为NULL表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数 返回值:成功返回0;失败返回错误码
绝大多数函数的名字以“pthread_”打头的函数
要使用这些函数库,要通过引入头文件<pthread.h> 链接这些线程函数库时要使用编译器命令的“-lpthread”选项
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
int gcnt = 100;
//新线程
void *ThreadRoutine(void *arg)
{
const char *threadname = (const char *)arg;
while(true)
{
std::cout<<"I am a new thread:" << threadname << ",pid: "<< getpid() << "gcnt:" << gcnt << "," << &gcnt << std::endl;
gcnt--;
sleep(1);
}
}
int main()
{
pthread_t tid1; //实际上pthread_t就是无符号长整形
//创建线程1
pthread_create(&tid1, NULL, ThreadRoutine, (void*)"thread 1");
sleep(2);
//主线程
while(true)
{
std::cout << "I am main thread" << std::endl;
sleep(1);
}
return 0;
}
通过
ps -aL 命令来查看线程id
现象:打印的pid是一样的,说明两个线程是属于同一个进程里的线程,因此获取的pid相同(理解:可以看看前文讲的现在的进程是怎样的)
LWP是用来区分线程的,全名是LIGHT WEIGHT PROCESSES轻量级进程(也就是线程)
在第一行中PID与LWP相同的就是主线程
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
int gcnt = 100;
void *ThreadRoutine(void *arg)
{
const char *threadname = (const char *)arg;
while(true)
{
std::cout<<"I am a new thread:" << threadname << ",pid: "<< getpid() << "gcnt:" << gcnt << "," << &gcnt << std::endl;
gcnt--;
sleep(1);
}
}
int main()
{
pthread_t tid1; //实际上pthread_t就是无符号长整形
//创建线程1
pthread_create(&tid1, NULL, ThreadRoutine, (void*)"thread 1");
sleep(2);
pthread_t tid2;
//创建线程2
pthread_create(&tid2, NULL, ThreadRoutine, (void*)"thread 2");
sleep(2);
pthread_t tid3;
//创建线程3
pthread_create(&tid3, NULL, ThreadRoutine, (void*)"thread 3");
sleep(2);
//主线程
while(true)
{
std::cout << "I am main thread" << std::endl;
sleep(1);
}
return 0;
}
现象:所有线程共享同一份地址空间(共享同一份资源,观察:每个线程上对gcnt变量的修改在全局上有效)
小结
今日的分享就到这里啦,如果本文存在疏漏或错误的地方,还请您能够指出!