当前位置: 首页 > article >正文

线程-4-线程库与线程封装

线程ID&进程地址空间布局

不存在叫tcb的,pthread就是tcb

库中,所有tcb按照数组存放

struct pthread     就是tcb

pthread_create返回线程ID(tid)

线程ID是其pthread地址

每个新线程的栈是create时申请的

新线程的栈是动态申请出来的

线程的局部存储(TLS)__thread

thread local storage

__thread int share_val

每个线程各有一个此变量

其他进程拿到此地址也可以访问,修改(但一般不会这样做)

线程局部存储只能用来修饰内置类型,不能修饰自定义类型(struct,class)

pthread库属于glibc

malloc底层用mmap实现

使用该空间时才通过缺页中断建立叶表映射虚拟/物理内存

pthread_create 通过pthread库来初始化tcb等各参数,之后通过软中断系统调用建立LWP,所以叫pthread做用户级库

封装pthread

不能令routine为类内普通函数,可为类内static函数(this指针占参数了)

封装code

tips

类的成员变量就是全局变量(类内空间的全局变量)

code

mythread.cc

#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <thread>

// 线程的局部存储
// __thread只能修饰内置类型
__thread int shared_value = 100;

std::string toHex(pthread_t tid)
{
    // 4. 进程内的函数,线程共享
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "0x%lx", tid);
    return buffer;
}

void *start(void *args)
{
    std::string name = static_cast<const char *>(args);
    sleep(1);
    while (true)
    {
        printf("I am a new thread, name: %s, shared_value: %d,  &shared_value: %p\n", name.c_str(), shared_value, &shared_value);
        sleep(1);
    }

    return nullptr;
}

int main()
{
    pthread_attr_t attr;

    
    pthread_t tid;
    pthread_create(&tid, nullptr, start, (void *)"thread-1");
    std::cout << "I am a new thread, name: main, " << toHex(pthread_self())
              << ", NEW thread id: " << toHex(tid) << std::endl;

    while (true)
    {
        printf("main thread, shared_value: %d,  &shared_value: %p\n", shared_value, &shared_value);
        shared_value += 10;
        sleep(1);
    }
    pthread_join(tid, nullptr);
    return 0;
}

// int *addr = nullptr;

// void *start1(void *args)
// {
//     std::string name = static_cast<const char *>(args);
//     int a = 100;
//     while (true)
//     {
//         std::cout << name << " local val a: " << a << std::endl;
//         sleep(1);
//     }
// }

// void *start(void *args)
// {
//     // 可以的!
//     // pid_t id = fork();
//     // if(id == 0)
//     // {
//     //     // ....
//     // }
//     // pthread_detach(pthread_self());
//     // std::string name = static_cast<const char *>(args);
//     // while (true)
//     // {
//     //     // if(addr != nullptr)
//     //     //std::cout << name << " mod val a: " << (*addr)++ << std::endl;
//     //     std::cout << "I am a new thread" << std::endl;
//     //     sleep(1);
//     //     // break;
//     // }
//     // return 0; // 9. 新线程return表示该线程退出
//     // exit(1); // 任何地方调用exit,表示进程退出!
//     // pthread_exit((void*)10);
// }

// int main()
// {
//     // // pthread_t tid1, tid2;
//     // pthread_t tid;
//     // pthread_create(&tid, nullptr, start, (void *)"thread-1");
//     // // pthread_detach(tid);
//     // sleep(5);

//     // // int n = pthread_cancel(tid);
//     // // std::cout << "取消线程: " << tid << std::endl;

//     // // sleep(5);

//     // void *ret = nullptr;
//     // int n = pthread_join(tid, &ret); //PTHREAD_CANCELED;
//     // std::cout << "new thread exit code: " << (long long int)ret << " ,n: " << n << std::endl;

//     // // pthread_create(&tid1, nullptr, start2, (void *)"thread-1");
//     // // pthread_join(tid1, nullptr);
//     // return 0; // 9. 主线程return,表示进程结束!
// }

// class ThreadData
// {
// public:
//     ThreadData()
//     {}
//     void Init(const std::string &name, int a, int b)
//     {
//         _name = name;
//         _a = a;
//         _b = b;
//     }
//     void Excute()
//     {
//         _result = _a + _b;
//     }
//     int Result(){ return _result; }
//     std::string Name(){ return _name; }
//     void SetId(pthread_t tid) { _tid = tid;}
//     pthread_t Id() { return _tid; }
//     int A(){return _a;}
//     int B(){return _b;}
//     ~ThreadData()
//     {}
// private:
//     std::string _name;
//     int _a;
//     int _b;
//     int _result;
//     pthread_t _tid;
// };

// // class outData
// // {

// // };

// // 5. 全局变量在线程内部是共享的
// int gval = 100;
// // std::queue<int> q;
// // char buffer[4096];

// std::string toHex(pthread_t tid)
// {
//     // 4. 进程内的函数,线程共享
//     char buffer[64];
//     snprintf(buffer, sizeof(buffer), "0x%lx", tid);
//     return buffer;
// }

// void *routine2(void *args)
// {
//     std::string name = static_cast<const char *>(args);
//     while (true)
//     {
//         // 3. 不加保护的情况下,显示器文件就是共享资源!
//         std::cout << "我是新线程,我的名字是: " << name << ", my tid is : " << toHex(pthread_self()) << ", 全局变量(只是检测):" << gval << std::endl;
//         sleep(1);
//         // 6. 线程一旦出现异常,可能会导致其他线程全部崩溃
//         // 6.1 信号
//         int *p = nullptr;
//         *p = 100;
//     }
//     return 0;
// }

// // 被重入了!!
// void *routine(void *args)
// {
//     //std::string name = static_cast<const char *>(args);
//     ThreadData *td = static_cast<ThreadData *>(args);
//     while (true)
//     {
//         // 3. 不加保护的情况下,显示器文件就是共享资源!
//         std::cout << "我是新线程,我的名字是: " << td->Name() << ", my tid is : " << toHex(pthread_self()) << ", 全局变量(会修改):" << gval << std::endl;
//         gval++;
//         td->Excute();
//         sleep(1);
//         break;
//     }
//     // 8.返回值问题: 返回参数,可以是变量,数字,对象!
//     // 8.1: 理论上,堆空间也是共享的!谁拿着堆空间的入口地址,谁就能访问该堆区!
//     // int *p = new int(10);
//     // return (void*)p; // 线程退出方式1:线程入口函数return,表示线程退出

//     return td;
// }

// #define NUM 10

// int main()
// {

//     // ThreadData td[NUM];
//     // // 准备我们要加工处理的数据
//     // for(int i = 0; i < NUM; i++)
//     // {
//     //     char id[64];
//     //     snprintf(id, sizeof(id), "thread-%d", i);
//     //     td[i].Init(id, i*10, i*20);
//     // }

//     // // 创建多线程
//     // for(int i = 0; i < NUM; i++)
//     // {
//     //     pthread_t id;
//     //     pthread_create(&id, nullptr, routine, &td[i]);
//     //     td[i].SetId(id);
//     // }

//     // // 等待多个线程
//     // for(int i =0; i< NUM;i++)
//     // {
//     //     pthread_join(td[i].Id(), nullptr);
//     // }

//     // // 汇总处理结果
//     // for(int i =0;i < NUM; i++)
//     // {
//     //     printf("td[%d]: %d+%d=%d[%ld]\n", i, td[i].A(), td[i].B(), td[i].Result(), td[i].Id());
//     // }
//     // 1. 新线程和main线程谁先运行,不确定
//     // 2. 线程创建出来,要对进程的时间片进行瓜分
//     // 8. 传参问题: 传递参数,可以是变量,数字,对象!
//     // pthread_t tid1;
//     // ThreadData *td = new ThreadData("thread-1", 10, 20);
//     // pthread_create(&tid1, nullptr, routine1, td);

//     // // 7. 线程创建之后,也是要被等待和回收的!
//     // // 7.1 理由:a. 类似僵尸进程的问题 b. 为了知道新线程的执行结果
//     // ThreadData *rtd = nullptr;
//     // int n = pthread_join(tid1, (void**)&rtd); // 我们可以保证,执行完毕,任务一定处理完了,结果变量一定已经被写入了!
//     // if(n != 0)
//     // {
//     //     std::cerr << "join error: " << n << ", " << strerror(n) << std::endl;
//     //     return 1;
//     // }
//     // std::cout << "join success!, ret: " << rtd->Result() << std::endl;
//     // delete td;

//     // pthread_t tid2;
//     // pthread_create(&tid2, nullptr, routine2, (void *)"thread-2");

//     // pthread_t tid3;
//     // pthread_create(&tid3, nullptr, routine, (void *)"thread-3");

//     // pthread_t tid4;
//     // pthread_create(&tid4, nullptr, routine, (void *)"thread-4");

//     // std::cout << "new thread id: " << tid << std::endl;
//     // printf("new thread id: 0x%lx\n", tid1);
//     // printf("new thread id: 0x%lx\n", tid2);
//     // printf("new thread id: 0x%lx\n", tid3);
//     // printf("new thread id: 0x%lx\n", tid4);

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

// // void *routine(void *args)
// // {
// //     std::string name = static_cast<const char *>(args);
// //     while (true)
// //     {
// //         std::cout << "我是新线程,我的名字是: " << name << std::endl;
// //         sleep(1);
// //     }
// //     return 0;
// // }

// // int main()
// // {
// //     std::thread t([](){
// //         while (true)
// //         {
// //             std::cout << "我是新线程,我的名字是 : new thread "  << std::endl;
// //             sleep(1);
// //         }
// //     });

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

// //     // pthread_t tid;
// //     // int n = pthread_create(&tid, nullptr, routine, (void *)"thread-1");
// //     // if (n != 0)
// //     // {
// //     //     std::cout << "create thread error: " << strerror(n) << std::endl;
// //     //     return 1;
// //     // }
// //     // while (true)
// //     // {
// //     //     std::cout << "我是main线程..."  << std::endl;
// //     //     sleep(1);
// //     // }
// // }

main.cc

#include "Thread.hpp"
#include <unordered_map>
#include <memory>

#define NUM 10

// using thread_ptr_t = std::shared_ptr<ThreadModule::Thread>;

class threadData
{
public:
    int max;
    int start;
};

void Count(threadData td)
{
    for (int i = td.start; i < td.max; i++)
    {
        std::cout << "i == " << i << std::endl;
        sleep(1);
    }
}

int main()
{
    threadData td;
    td.max = 60;
    td.start = 50;
    ThreadModule::Thread<threadData> t(Count, td);
    // ThreadModule::Thread<int> t(Count, 10);

    t.Start();

    t.Join();

    // 先描述,在组织!
    // std::unordered_map<std::string, thread_ptr_t> threads;
    // // 如果我要创建多线程呢???
    // for (int i = 0; i < NUM; i++)
    // {
    //     thread_ptr_t t = std::make_shared<ThreadModule::Thread>([](){
    //         while(true)
    //         {
    //             std::cout << "hello world" << std::endl;
    //             sleep(1);
    //         }
    //     });
    //     threads[t->Name()] = t;
    // }

    // for(auto &thread:threads)
    // {
    //     thread.second->Start();
    // }

    // for(auto &thread:threads)
    // {
    //     thread.second->Join();
    // }

    // ThreadModule::Thread t([](){
    //     while(true)
    //     {
    //         std::cout << "hello world" << std::endl;
    //         sleep(1);
    //     }
    // });

    // t.Start();
    // std::cout << t.Name() << "is running" << std::endl;
    // sleep(5);

    // t.Stop();
    // std::cout << "Stop thread : " << t.Name()<< std::endl;
    // sleep(1);
    // t.Join();
    // std::cout << "Join thread : " << t.Name()<< std::endl;

    return 0;
}

thread.hpp

#ifndef _THREAD_HPP__
#define _THREAD_HPP__

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

// v2
namespace ThreadModule
{
    static int number = 1;
    enum class TSTATUS
    {
        NEW,
        RUNNING,
        STOP
    };

    template <typename T>
    class Thread
    {
        using func_t = std::function<void(T)>;
    private:
        // 成员方法!
        static void *Routine(void *args)
        {
            Thread<T> *t = static_cast<Thread<T> *>(args);
            t->_status = TSTATUS::RUNNING;
            t->_func(t->_data);
            return nullptr;
        }
        void EnableDetach() { _joinable = false; }

    public:
        Thread(func_t func, T data) : _func(func), _data(data), _status(TSTATUS::NEW), _joinable(true)
        {
            _name = "Thread-" + std::to_string(number++);
            _pid = getpid();
        }
        bool Start()
        {
            if (_status != TSTATUS::RUNNING)
            {
                int n = ::pthread_create(&_tid, nullptr, Routine, this); // TODO
                if (n != 0)
                    return false;
                return true;
            }
            return false;
        }
        bool Stop()
        {
            if (_status == TSTATUS::RUNNING)
            {
                int n = ::pthread_cancel(_tid);
                if (n != 0)
                    return false;
                _status = TSTATUS::STOP;
                return true;
            }
            return false;
        }
        bool Join()
        {
            if (_joinable)
            {
                int n = ::pthread_join(_tid, nullptr);
                if (n != 0)
                    return false;
                _status = TSTATUS::STOP;
                return true;
            }
            return false;
        }
        void Detach()
        {
            EnableDetach();
            pthread_detach(_tid);
        }
        bool IsJoinable() { return _joinable; }
        std::string Name() { return _name; }
        ~Thread()
        {
        }

    private:
        std::string _name;
        pthread_t _tid;
        pid_t _pid;
        bool _joinable; // 是否是分离的,默认不是
        func_t _func;
        TSTATUS _status;
        T _data;
    };
}

// v1
// namespace ThreadModule
// {
//     using func_t = std::function<void()>;
//     static int number = 1;
//     enum class TSTATUS
//     {
//         NEW,
//         RUNNING,
//         STOP
//     };

//     class Thread
//     {
//     private:
//         // 成员方法!
//         static void *Routine(void *args)
//         {
//             Thread *t = static_cast<Thread *>(args);
//             t->_status = TSTATUS::RUNNING;
//             t->_func();
//             return nullptr;
//         }
//         void EnableDetach() { _joinable = false; }

//     public:
//         Thread(func_t func) : _func(func), _status(TSTATUS::NEW), _joinable(true)
//         {
//             _name = "Thread-" + std::to_string(number++);
//             _pid = getpid();
//         }
//         bool Start()
//         {
//             if (_status != TSTATUS::RUNNING)
//             {
//                 int n = ::pthread_create(&_tid, nullptr, Routine, this); // TODO
//                 if (n != 0)
//                     return false;
//                 return true;
//             }
//             return false;
//         }
//         bool Stop()
//         {
//             if (_status == TSTATUS::RUNNING)
//             {
//                 int n = ::pthread_cancel(_tid);
//                 if (n != 0)
//                     return false;
//                 _status = TSTATUS::STOP;
//                 return true;
//             }
//             return false;
//         }
//         bool Join()
//         {
//             if (_joinable)
//             {
//                 int n = ::pthread_join(_tid, nullptr);
//                 if (n != 0)
//                     return false;
//                 _status = TSTATUS::STOP;
//                 return true;
//             }
//             return false;
//         }
//         void Detach()
//         {
//             EnableDetach();
//             pthread_detach(_tid);
//         }
//         bool IsJoinable() { return _joinable; }
//         std::string Name() {return _name;}
//         ~Thread()
//         {
//         }

//     private:
//         std::string _name;
//         pthread_t _tid;
//         pid_t _pid;
//         bool _joinable; // 是否是分离的,默认不是
//         func_t _func;
//         TSTATUS _status;
//     };
// }

#endif

ticket.cc

#include <iostream>
#include <vector>
#include "Thread.hpp"
#include <mutex>

using namespace ThreadModule;

#define NUM 4

// 1. 锁本身是全局的,那么锁也是共享资源!谁保证锁的安全??
// pthread_mutex:加锁和解锁被设计成为原子的了 --- TODO??
// 2. 如何看待锁呢?二元信号量就是锁!
//    2.1 加锁本质就是对资源展开预订!
//    2.2 整体使用资源!!
// 3. 如果申请锁的时候,锁被别人已经拿走了,怎么办?其他线程要进行阻塞等待
// 4. 线程在访问临界区代码的时候,可以不可以切换??可以切换!!
//    4.1 我被切走的时候,别人能进来吗??不能!我是抱着锁,被切换的!!不就是串行吗!效率低的原因!原子性!
// 5. 不遵守这个约定??bug!
// pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int ticketnum = 10000; // 共享资源,临界资源
std::mutex gmtx;

class ThreadData
{
public:
    std::string name;
    pthread_mutex_t *lock_ptr;
};

void Ticket(ThreadData &td)
{
    while (true)
    {
        gmtx.lock();
        // pthread_mutex_lock(td.lock_ptr); // 加锁
        if (ticketnum > 0)
        {
            usleep(1000);

            // 1. 抢票
            printf("get a new ticket, who get it: %s, id: %d\n", td.name.c_str(), ticketnum--);
            gmtx.unlock();
            // pthread_mutex_unlock(td.lock_ptr); // ??
            // 2. 入库模拟
            usleep(50);
        }
        else
        {
            // pthread_mutex_unlock(td.lock_ptr); // ??
            gmtx.unlock();
            break;
        }
    }
}

int main()
{
    pthread_mutex_t lock;
    pthread_mutex_init(&lock, nullptr);

    // 1. 构建线程对象
    std::vector<Thread<ThreadData>> threads;

    for (int i = 0; i < NUM; i++)
    {
        ThreadData *td = new ThreadData();
        td->lock_ptr = &lock;
        threads.emplace_back(Ticket, *td);
        td->name = threads.back().Name();
    }

    // 2. 启动线程
    for (auto &thread : threads)
    {
        thread.Start();
    }

    // 3. 等待线程
    for (auto &thread : threads)
    {
        thread.Join();
    }

    pthread_mutex_destroy(&lock);

    return 0;
}

mutex.hpp

#pragma once
#include <iostream>
#include <pthread.h>

namespace LockModule
{
    class Mutex
    {
    public:
        Mutex(const Mutex&) = delete;
        const Mutex& operator = (const Mutex&) = delete;
        Mutex()
        {
            int n = ::pthread_mutex_init(&_lock, nullptr);
            (void)n;
        }
        ~Mutex()
        {
            int n = ::pthread_mutex_destroy(&_lock);
            (void)n;
        }
        void Lock()
        {
            int n = ::pthread_mutex_lock(&_lock);
            (void)n;
        }
        void Unlock()
        {
            int n = ::pthread_mutex_unlock(&_lock);
            (void)n;
        }

    private:
        pthread_mutex_t _lock;
    };

    class LockGuard
    {
    public:
        LockGuard(Mutex &mtx):_mtx(mtx)
        {
            _mtx.Lock();
        }
        ~LockGuard()
        {
            _mtx.Unlock();
        }
    private:
        Mutex &_mtx;
    };
}

 main.cc

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>

int ticket = 0;
pthread_mutex_t mutex;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *route(void *arg)
{
    char *id = (char *)arg;
    while (1)
    {
        pthread_mutex_lock(&mutex);
        if (ticket > 0)
        {
            usleep(1000);
            printf("%s sells ticket:%d\n", id, ticket);
            ticket--;
            pthread_mutex_unlock(&mutex);
        }
        else
        {
            printf("%s wait on cond!\n", id);
            pthread_cond_wait(&cond, &mutex); //醒来的时候,会重新申请锁!!
            printf("%s 被叫醒了\n", id);
        }
        pthread_mutex_unlock(&mutex);
    }
    return nullptr;
}

int main(void)
{
    pthread_t t1, t2, t3, t4;

    pthread_mutex_init(&mutex, NULL);

    pthread_create(&t1, NULL, route, (void *)"thread 1");
    pthread_create(&t2, NULL, route, (void *)"thread 2");
    pthread_create(&t3, NULL, route, (void *)"thread 3");
    pthread_create(&t4, NULL, route, (void *)"thread 4");

    int cnt = 10;

    while(true)
    {
        sleep(5);
        ticket += cnt;
        printf("主线程放票喽, ticket: %d\n", ticket);
        pthread_cond_signal(&cond);
    }


    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);
    pthread_join(t4, NULL);
    pthread_mutex_destroy(&mutex);
}

板书笔记


http://www.kler.cn/a/459420.html

相关文章:

  • 交换机关于环路、接口绑定、链路聚合的相关知识
  • xilinx的高速接口构成原理和连接结构及ibert工具的使用-以k7 GTX为例
  • 实时数仓与离线数仓的全面对比
  • 六十一:HTTP/2的问题及HTTP/3的意义
  • C# 服务调用RFC函数获取物料信息,并输出生成Excel文件
  • ES_如何设置ElasticSearch 8.0版本的匿名访问以及https_http模式的互相切换
  • 完整的 FFmpeg 命令使用教程
  • 【PyCharm】如何把本地整个项目同步到服务器?
  • 在web.xml中配置Servlet映射
  • 【Next.js】002-路由篇|App Router
  • 冒泡排序c语言
  • 百度PaddleSpeech识别大音频文件报错
  • vim/vi编辑器
  • 彩虹表的攻击与防御
  • 使用 IDE生成 Java Doc
  • C++基础:SGI STL二级空间配置器内存池
  • 【数据分析处理之缺失值】
  • Kafka消息不丢失与重复消费问题解决方案总结
  • 短视频矩阵系统搭建开发指导
  • 什么是模块?在Node.js中,每一个文件都被视为一个模块来处理
  • [Linux]从零开始的Nginx反向代理配置及运用教程
  • python3中条件判断语句:match...case语句
  • 后端Java开发如何向LLM方向转型
  • Python爬虫:亚马逊评论数据在市场分析中的应用
  • 【实验记录】动手实现一个简单的神经网络实验(一)
  • Nginx 配置前端后端服务