理解线程id和简单封装原生线程库

一、理解线程id

首先我们要知道给用户提供的线程id不是内核里面LWP(轻量级进程id),而是pthread库自己维护的一个唯一值。

我们理解为什么线程id不是内核里面LWP,因为用户没有权限使用内核里面的字段,那是专门给OS管理线程用的。

但是为什么要pthread库来帮我们用户维护用户级线程id呢?

因为Linux内核根本就不存在线程的概念,所谓用户口中的线程在Linux眼里就是轻量级进程,之后理解不在赘述具体参考文章http://t.csdnimg.cn/jTGGP中pthread库介绍。

内核级理解:

所以我们清楚的看到返回给用户的线程id就是一个线程控制块在虚拟地址空间的起始位置。

类比FILE对象,其实就在c标准库中,返回的是FILE*就是地址。

所以 pthread_join() 函数就是通过tid找到存在虚拟地址空间中的线程结构体对象,把里面的退出信息拷贝出来返回。

操作系统内示意图:

二、简单封装原生线程库

thread.hpp

#pragma once
#include<pthread.h>
#include<iostream>
#include<string>
using namespace std;

namespace Thread
{
    //线程执行方法
    typedef void(*func_t)(const string& name);

    class Thread
    {
    public:
        //线程执行方法
        void Excute()
        {
            cout << _name << " is running" << endl; 
            _isrunning = true;
            _func(_name);
            _isrunning = false;
        }

    public:
        Thread(const string& name, func_t func)
            :_name(name)
            ,_func(func)
        {
            cout << "create " << name << " done" << endl; 
        }


        //线程执行回调方法
        //设成静态方法,函数就不会自带this指针,类型就匹配上了
        //但是此时就无法调类的回调函数,在create函数中传参即可
        static void* ThreadRoutine(void* args)
        {
            //获得当前线程对象
            Thread* self = static_cast<Thread*>(args);
            //调用线程执行方法
            self->Excute();
            return nullptr;
        }


        bool Start()
        {
            int n = ::pthread_create(&_tid, nullptr, ThreadRoutine, this);
            if (n != 0)
                return false;
            return true;
        }

        string Status()
        {
            if(_isrunning) 
                return "running";
            else 
                return "sleep";
        }

        string GetName()
        {
            return _name;
        }

        void Stop()
        {
            if(_isrunning = true)
            {
                ::pthread_cancel(_tid);
                _isrunning = false;
                cout << _name << " stop" << endl; 
            }
        }

        void Join()
        {
            if(!_isrunning)
            {
                ::pthread_join(_tid, nullptr);
                cout << _name << " join done" << endl; 
            }
        }


        ~Thread()
        {
        }
    private:
        string _name;
        pthread_t _tid;
        bool _isrunning = false;
        func_t _func; //线程执行的回调函数
    };
}

main.cc

#include<iostream>
#include"thread.hpp"
#include<unistd.h>
#include<vector>
using namespace Thread;
using namespace std;

void Print(const string& name)
{
    int cnt = 0;
    while(1)
    {
        cout << name << " is running, cnt: " << cnt++ << endl;
        sleep(1);
    }
}

const int num = 10;

int main()
{
    //创建线程
    vector<Thread::Thread> threads;
    for(int i = 0; i < num; i++)
    {
        string name = "thread-" + to_string(i + 1);
        threads.emplace_back(name, Print);
        sleep(1);
    }

    //统一启动
    for(auto& thread : threads)
    {
        thread.Start();
    }

    sleep(10);

    //统一结束
    for(auto& thread : threads)
    {
        thread.Stop();
    }

    //统一回收
    for(auto& thread : threads)
    {
        thread.Join();
    }


    // Thread::Thread t("thread-1", Print);
    // t.Start();

    // cout << t.GetName() << " status: " << t.Status() << endl;
    // sleep(10);
    // cout << t.GetName() << " status: " << t.Status() << endl;
    // t.Stop();
    // sleep(1);
    // cout << t.GetName() << " status: " << t.Status() << endl;

    // t.Join();
    // cout << "join done" << endl;


    return 0;
}

三、线程的局部存储

对于一个全局变量,一个进程中任意线程都能进行修改,另外的线程也可以看到变化,因为线程共享进程的大部分数据。

在LInux中我们用 __thread修饰全局变量(只能修饰内置类型)就能让全局变量在所有线程各有一份,地址也不同,这就能实现每一个线程都有属于自己的变量,这就是线程的局部存储。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值