0
点赞
收藏
分享

微信扫一扫

企业工程项目管理系统源码-专注项目数字化管理-Java工程管理-二次开发

谷中百合517 2023-05-23 阅读 95

目录

地址空间和页表

如何看待地址空间和页表

虚拟地址如何转化到物理地址的

线程与进程的关系

什么叫进程?

什么叫线程?

如何看待我们之前学习进程时,对应的进程概念呢?和今天的冲突吗?

windows线程与linux线程

代码示例:

轻量级进程

线程的概念

举个例子(见见猪跑)

代码示例:

运行结果:

什么资源是线程私有的?

什么是线程?

cache刷新策略

一个线程如果出现了异常,会影响其他线程吗? 为什么?

给线程发信号

使用vfork函数

线程控制

线程的创建

pthread_create函数

创建多个线程

线程终止

线程的等待

概念

pthread_join函数

线程取消

概念

在C++中创建线程

分离线程

分离线程

pthread_detach函数

原生线程库

概念 

封装一个原生线程库

Thread.hpp

mythread.cc


地址空间和页表

如何看待地址空间和页表

虚拟地址如何转化到物理地址的

 

物理内存因为OS也要对其做管理,对物理内存进行了分页

struct Page{ // 内存的属性-- 4KB
}

一个个小块的物理内存为页框。

线程与进程的关系

线程:进程内的一个执行流

linux中是没有真正的线程的。

如果我们OS真的要专门设计“线程”概念,OS未来要不要管理这个线程呢?

单纯从线程调度角度,线程和进程有很多地方是重叠的!

什么叫进程?

内核视角:承担分配系统资源的基本实体。

什么叫线程?

CPU调度的基本单位!

如何看待我们之前学习进程时,对应的进程概念呢?和今天的冲突吗?

在进程中

好处是什么?  

windows线程与linux线程

如何理解?举一个例子来说明!

代码示例:


#include <iostream>
#include <pthread.h>
#include <assert.h>
#include <unistd.h>

using namespace std;


// 新线程
void *thread_routine(void *args)
{   
    while(true)
    {
        cout<<"我是新线程,我正在运行!"<<endl;
        sleep(1);
    }

}

int main()

{

    pthread_t tid;
    int n=pthread_create(&tid,0,thread_routine\
    ,(void*)"thread one");
    assert(0==n);
    (void)n;


    // 主线程
    while(true)
    {
        cout<<"我是主线程,我正在运行!"<<endl;
        sleep(1);
    }




    return 0;
}

代码解释:

轻量级进程

查看轻量级进程的指令

轻量级进程ID

PID与LWP


CPU调度的时候,是以哪一个id为标识符表示特定一个执行流的呢?

当内部只有一个执行流的时候,内部只有一个主线程。也可以将我们传入的线程名字给打印出来。

代码如下:


// 新线程
void *thread_routine(void *args)
{

    const char *name = (const char *)args;

    while (true)
    {
        cout << "我是新线程,我正在运行!"
             << "name:" << name << endl;
        sleep(1);
    }
}

运行结果:

 

线程的概念

举个例子(见见猪跑)

线程一旦被创建,几乎所有的资源都是被所有的线程所共享的。

代码示例:


#include <iostream>
#include <pthread.h>
#include <cstdio>
#include <assert.h>
#include <unistd.h>

using namespace std;

int g_val = 0;

string fun()
{
    return "我是一个独立的方法";
}


// 新线程
void *thread_routine(void *args)
{

    const char *name = (const char *)args;

    while (true)
    {
        cout << "我是新线程,我正在运行!"
             << "name:" << name << ": " << fun()<<" ";
        cout << "g_val: " << g_val++ << "&g_val: " << &g_val << endl;
        // fun();
        sleep(1);
    }
}

int main()

{

    pthread_t tid;
    int n = pthread_create(&tid, 0, thread_routine, (void *)"thread one");
    assert(0 == n);
    (void)n;

    // 主线程
    while (true)
    {
        char tidbuffer[64];
        snprintf(tidbuffer, sizeof(tidbuffer), "0x%x", tid);
        // cout << tidbuffer;
        cout << "我是主线程,我正在运行!,我创建出来的线程tid: "\
        << tidbuffer << ": " << fun()<<" ";
        cout << "g_val: " << g_val << "&g_val: " << &g_val << endl;

        // printf("0x%x",tid);
        fun();
        sleep(1);
    }

    return 0;
}

运行结果:

结论:

因此我们发现,两个线程共享了这个全局的函数。
并且同一个全局变量两个线程的地址一样,并且当有一个线程对该全局变量修改的时候,另一个线程也能看到   

什么资源是线程私有的?

什么是线程?

cache刷新策略

一个线程如果出现了异常,会影响其他线程吗? 为什么?

代码示例:


#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>

using namespace std;

void *start_routine(void *args)
{
    // 一个线程如果出现了异常,会影响其他线程吗? 为什么?
    // 会的,健壮性/鲁棒性较差
    string name = static_cast<const char *>(args); // 安全的进行强制类型转化
    while (true)
    {
        cout << "new thread create success, name: " << name << endl;
        sleep(1);
        int *p=nullptr;
        *p=0;
    }
}

int main()
{

    pthread_t id;

    pthread_create(&id, nullptr, start_routine, (void *)"thread one");

    while (true)
    {
        cout << "new thread create success, name: main thread" << endl;
        sleep(1);
    }
}



运行结果:

给线程发信号

使用vfork函数

线程控制

线程的创建

pthread_create函数

功能:

函数原型:

参数


错误码的解析:
 

创建多个线程

代码示例:

#include <iostream>
#include <pthread.h>
#include <vector>
#include <string>
#include <unistd.h>

using namespace std;

// 创建一个结构体来存放线程的基本属性
class ThreadData
{
public:
    // 线程id
    pthread_t tid;
    // 线程的名字
    char namebuffer[64];
};

    // 创建新线程
//1. start_routine,现在是被几个线程执行呢? 10 ,这个函数是什么状态
// 2.  该函数是可重入函数吗?
void *start_routine(void *args)
{
    sleep(1);
    // 一个线程如果出现了异常,会影响其他线程吗? 为什么?
    // 会的,健壮性/鲁棒性较差
    ThreadData *td = static_cast<ThreadData *>(args); // 安全的进行强制类型转化
    int cnt = 10;
    while (cnt)
    {
        cout << "new thread create success, name: " << td->namebuffer
             << "cnt: " << cnt-- << endl;
        sleep(1);

    }
    delete td;
    return nullptr; //线程结束的,return的时候,线程就终止了
}

int main()
{
    // 1.我们想创建一批线程

    vector<ThreadData *> threads;
#define NUM 10

    for (int i = 0; i < NUM; i++)
    {
        ThreadData *td = new ThreadData();

        snprintf(td->namebuffer, sizeof(td->namebuffer), "%s:%2d", "thread", i+1);

        pthread_create(&td->tid, nullptr, start_routine, td);
        threads.push_back(td);
        // sleep(1);
    }

    for(auto &iter : threads)
    {
        cout<<"create thread: "<<iter->namebuffer<<" : "<<iter->tid<<"  success"<<endl;
    }

    while (true)
    {
        cout << "new thread create success, name: main thread" << endl;
        sleep(1);
    }

    return 0;
}

线程终止

如何终止

退出方法

线程的等待

概念

那我们可以不关心退出信息吗?

pthread_join函数

原型

int pthread_join(pthread_t thread,void **retval);

参数

代码示例:目的是使用join来获取新线程退出后的退出信息


#include <iostream>
#include <pthread.h>
#include <vector>
#include <string>
#include<assert.h>
#include <unistd.h>

using namespace std;

// 创建一个结构体来存放线程的基本属性
class ThreadData
{
public:
    // 线程id
    pthread_t tid;
    // 线程的名字
    char namebuffer[64];
    // 线程的编号
    int number;
};
class ThreadReturn
{
public:
    int exit_code;
    int exit_result;
};



    // 创建新线程
//1. start_routine,现在是被几个线程执行呢? 10 ,这个函数是什么状态
//2.  该函数是可重入函数吗?
//3.在函数内定义的变量,都叫做局部变量,具有临时性 -- 今天依旧适用-- 在多线程情况下,也没有问题 -- 其实每一个线程都有自己独立的栈结构!

void *start_routine(void *args)
{
    // sleep(1);
    // 一个线程如果出现了异常,会影响其他线程吗? 为什么?
    // 会的,健壮性/鲁棒性较差
    ThreadData *td = static_cast<ThreadData *>(args); // 安全的进行强制类型转化
    int cnt = 5;
    while (cnt)
    {
        cout<<"cnt: "<<cnt<<" &cnt:"<<&cnt<<endl;
        cnt--;
        // cout << "new thread create success, name: " << td->namebuffer
        //      << "cnt: " << cnt-- << endl;
        // pthread_exit(nullptr);
        sleep(1);

    }
    
    ThreadReturn *tr=new ThreadReturn();
    tr->exit_code=1;
    tr->exit_result=106;

    return (void*)tr;// 右值
   

}


int main()
{
    // 1.我们想创建一批线程

    vector<ThreadData *> threads;
#define NUM 10

    for (int i = 0; i < NUM; i++)
    {
        ThreadData *td = new ThreadData();

        // 用来记录线程的编号
        td->number=i+1;

        snprintf(td->namebuffer, sizeof(td->namebuffer), "%s:%2d", "thread", i+1);

        pthread_create(&td->tid, nullptr, start_routine, td);
        threads.push_back(td);
       
    }

    for(auto &iter : threads)
    {
        cout<<"create thread: "<<iter->namebuffer<<" : "<<iter->tid<<"  success"<<endl;
    }

    for(auto &iter : threads)
    {   
        ThreadReturn *ret=nullptr;
        // void *ret=nullptr;// 注意:是void *
        int n= pthread_join(iter->tid,(void**)&ret);
        
        assert(0==n);
        
        
        cout<<"join : "<<iter->namebuffer << " success,exit_code: "<<\
        ret->exit_code<<", exit_result: "<<ret->exit_result<<endl;

        delete iter;
    }

    cout<<"main thread quit "<<endl;


    return 0;
}




为什么没有见到线程退出的时候,对应的退出信号??

线程取消

概念

代码示例:线程的取消所使用函数:pthread_cancel
 




#include <iostream>
#include <pthread.h>
#include <vector>
#include <string>
#include <assert.h>
#include <unistd.h>

using namespace std;

// 创建一个结构体来存放线程的基本属性
class ThreadData
{
public:
    // 线程id
    pthread_t tid;
    // 线程的名字
    char namebuffer[64];
    // 线程的编号
    int number;
};
class ThreadReturn
{
public:
    int exit_code;
    int exit_result;
};

// 创建新线程
// 1. start_routine,现在是被几个线程执行呢? 10 ,这个函数是什么状态
// 2.  该函数是可重入函数吗?
// 3.在函数内定义的变量,都叫做局部变量,具有临时性 -- 今天依旧适用-- 在多线程情况下,也没有问题 -- 其实每一个线程都有自己独立的栈结构!

void *start_routine(void *args)
{
    
    ThreadData *td = static_cast<ThreadData *>(args); // 安全的进行强制类型转化
    int cnt = 5;
    while (cnt)
    {
        cout << "cnt: " << cnt << " &cnt:" << &cnt << endl;
        cnt--;
        
        sleep(1);
    }

    ThreadReturn *tr = new ThreadReturn();
    tr->exit_code = 1;
    tr->exit_result = 106;

    return (void *)tr; // 右值
    
}

int main()
{
    // 1.我们想创建一批线程

    vector<ThreadData *> threads;
#define NUM 10

    for (int i = 0; i < NUM; i++)
    {
        ThreadData *td = new ThreadData();

        // 用来记录线程的编号
        td->number = i + 1;

        snprintf(td->namebuffer, sizeof(td->namebuffer), "%s:%2d", "thread", i + 1);

        pthread_create(&td->tid, nullptr, start_routine, td);
        threads.push_back(td);
        // sleep(1);
    }

    for (auto &iter : threads)
    {
        cout << "create thread: " << iter->namebuffer << " : " << iter->tid << "  success" << endl;
    }

    // 线程是可以被cancel取消的,注意:线程被取消,前提是这个线程已经跑起来了
    // 线程如果是被取消的,那么退出码为-1 
    sleep(5);

    for (int i=0;i<threads.size()/2;i++)
    {
        pthread_cancel(threads[i]->tid);
        cout << "pthread_cancel :  " << threads[i]->tid << "  success" << endl;
    }

    for (auto &iter : threads)
    {
        void *ret = nullptr;
        
        assert(0 == n);
       

        cout << "join : " << iter->namebuffer << " success,exit_code: " <<(long long)ret<<endl;
        delete iter;
    }

    cout << "main thread quit " << endl;

    
    return 0;
}

在C++中创建线程


#include <iostream>
#include <thread>
#include <unistd.h>

void thread_run()
{
    while (true)
    {
        std::cout << "我是新线程..." << std::endl;
        sleep(1);
    }
}

int main()
{

    std::thread t1(thread_run);

    while(true)
    {
        std::cout<<"我是主线程..."<<std::endl;
        sleep(1);
    }

    t1.join();

    

    return 0;
}

结论:

分离线程

线程是可以等待的、等待的时候,阻塞式等待。
如果我们不想等待呢?

分离线程

使用pthread_self()可以获取当前线程的id。

代码示例:


#include <iostream>
#include <pthread.h>
#include <cstdio>
#include <unistd.h>

std::string changeId(const pthread_t &thread_id)
{
    char tid[128];
    snprintf(tid, sizeof(tid), "0x%x", thread_id);
    return tid;
}

void *start_routine(void *args)
{
    std::string threadname = static_cast<const char *>(args);

    while (true)
    {
        char tid[128];
        snprintf(tid, sizeof(tid), "0x%x", pthread_self());
        std::cout << threadname << "  running ... " << changeId(pthread_self()) << std::endl;
        sleep(1);
    }
}
int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, start_routine, (void *)"thread one");

    std::string main_id = changeId(pthread_self());

    std::cout << "main  running ... new thread id:  " << changeId(tid) << "main thread id: " << main_id << std::endl;

    pthread_join(tid, nullptr);

    return 0;
}

代码结论:

pthread_detach函数

原型

int pthread_detach(pthread_t thread);

 代码示例:


#include <iostream>
#include <pthread.h>
#include <cstdio>
#include <unistd.h>
#include <cstring>

std::string changeId(const pthread_t &thread_id)
{
    char tid[128];
    snprintf(tid, sizeof(tid), "0x%x", thread_id);
    return tid;
}

void *start_routine(void *args)
{ 
    std::string threadname = static_cast<const char *>(args);

    int cnt=5;
    while (cnt--)
    {
        std::cout << threadname << "  running ... " << changeId(pthread_self()) << std::endl;
        sleep(1);
    }
}
int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, start_routine, (void *)"thread one");

    std::string main_id = changeId(pthread_self());
    pthread_detach(tid);




    std::cout << "main  running ... new thread id:  " << changeId(tid) << "main thread id: " << main_id << std::endl;
    // sleep(5);
    // 一个线程默认是joinable的,如果设置了分离状态,就不能进行等待了
    int n = pthread_join(tid, nullptr);

    std::cout<<"result : "<<n<<": "<<strerror(n)<<std::endl;

    return 0;
}


原生线程库

概念 

 


原生线程库中,可能要存在多个线程--你用这些接口创建了线程,别人可以同时再用吗?
要不要对线程进行管理呢?

线程的属性:


Linux的方案:


线程id是该线程在线程库中该线程TCB的地址。独立栈在共享区的库中。


栈的分布。


线程的局部存储:


封装一个原生线程库

Thread.hpp

#pragma once

#include <iostream>
#include <pthread.h>
#include <functional>
#include <cassert>
#include <cstring>
#include <string>

class Thread;

// 上下文
class Context
{
public:
    Thread *this_;
    void *args_;
public:
    Context():this_(nullptr),args_(nullptr)
    {}
    ~Context()
    {}
};





class Thread
{
public:
    typedef std::function<void *(void *)> func_t;
    const int num = 1024;

public:
    Thread(func_t func, void *args, int number)
        : func_(func), args_(args)
    {

        // name_="thread-";
        // name_+=std::to_string(number);

        char buffer[num];
        snprintf(buffer, sizeof buffer, "thread-%d", number);
        name_ = buffer;
        
        // 异常 == if : 意料之外用异常或者if判断
        // assert:意料之中用assert

        Context *ctx=new Context();

        ctx->this_=this;
        ctx->args_=args_;



        int n = pthread_create(&tid_, nullptr, start_routine,ctx); // TODO
        assert(n == 0);
        (void)n;
        // 编译debug的方式发布的时候是存在的,release方式发布,
        // assert就不存在l,n就是一个定义,
        // 但是没有使用的变量,有些编译器下会有warning
    }

    // 在类内创建线程,想让线程执行对应的方法,需要将方法设置成为static
    // 类内成员,有缺省参数!在第一参数中包含了一个this指针
    static void *start_routine(void *args) 
    {
        Context *ctx=static_cast<Context*>(args);
        
        void *ret=ctx->this_->run(ctx->args_);

        delete ctx;

        return ret;

        // 静态方法不能调用成员方法或者成员变量
        // return func_(args_);

    }

   

    void join()
    {
        int n = pthread_join(tid_, nullptr);
        assert(n == 0);

        (void)n;
    }


    void *run(void *args)
    {
        return func_(args);
    }


    ~Thread()
    {
        // do northing
    }

private:
    std::string name_;
    func_t func_;
    void *args_;

    pthread_t tid_;
};

mythread.cc

#include <iostream>
#include <pthread.h>
#include <cstdio>
#include <unistd.h>
#include <memory>
#include <cstring>
#include "Thread.hpp"



void *thread_run(void *args)
{
    std::string work_type=static_cast<const char*>(args);

    while(true)
    {
        std::cout<<"我是一个新线程,我正在做:"<<work_type<<std::endl;
        sleep(1);
    }
}


int main()
{

    std::unique_ptr<Thread> thread1(new Thread(thread_run,(void*)"hellothread",1));
    std::unique_ptr<Thread> thread2(new Thread(thread_run,(void*)"countthread",2));
    std::unique_ptr<Thread> thread3(new Thread(thread_run,(void*)"logthread",3));
    

    thread1->join();
    thread2->join();
    thread3->join();




    return 0;
}
举报

相关推荐

0 条评论