c++线程

作者: arkliu | 来源:发表于2022-11-27 09:33 被阅读0次

    使用thread创建线程

    #include <iostream>
    #include<string>
    #include<thread>
    using namespace std;    
    
    void fun(int age, string name) {
        cout <<"age ="<<age<<"  name = "<<name<<endl;
    }
    
    int main() {
        thread t1(fun, 22, "lisi");
        t1.join(); //回收线程t1的资源
        return 0;
    }
    
    image.png

    线程资源回收

    虽然同一个进程的多尔线程共享进程的栈空间,但是每个子线程在整个栈中拥有自己私有的栈空间,所以线程结束时候需要回收资源

    回收资源有两种方法:

    • 在主程序中,调用join()成员函数等待子线程退出,回收它的资源,如果子线程已退出,join()函数立即返回,否则会产生阻塞,知道子线程退出
    • 在子线程中,调用detach()成员寒素,分离子线程,子线程退出时,系统自动回收资源
      用joinable()成员函数可以判断子线程的分离状态,函数返回bool类型

    this_thread的全局函数

    c11提供了命名空间this_thread 来表示当前线程,该命名空间中有四个函数

    • get_id() 获取线程id
    cout << "thread_id = "<<this_thread::get_id()<<endl;
    
    • sleep_for() 让线程休眠一段时间
    // 休眠1秒
    this_thread::sleep_for(chrono::seconds(1));
    
    • sleep_until() 让线程休眠到指定时间点(可实现定时任务)
    • yield() 让线程主动让出自己已经抢到的cpu时间片

    call_once函数

    在多线程环境中,某些函数只能被调用一次,此时可以用std::call_once()来保证某个函数只被调用一次

    #include <iostream>
    #include<string>
    #include<thread>
    #include<mutex> // std::once_flag h和std::call_once需要包含这个头文件
    using namespace std;    
    
    once_flag onceflag;
    
    void once_func(const string str) {
        cout << "once_func :"<<str<<endl;
    }
    
    void fun(int age, string name) {
        call_once(onceflag, once_func, "我需要在多线程中,只被执行一次");
        cout <<"age ="<<age<<"  name = "<<name<<endl;
    }
    
    int main() {
        thread t1(fun, 22, "lisi");
        thread t2(fun, 33, "zhangsan");
        t1.join();
        t2.join();
        return 0;
    }
    

    native_handle函数

    c11定义了线程标准,不同的平台和编译器在实现的时候本质上都是对操作系统的线程库进行封装,会损失一部分功能

    所以thread类提供了native_handle()成员函数,用于获得与操作系统相关的原生线程句柄,操作系统原生的线程库就可以原生线程句柄操作线程。

    线程同步

    • 互斥锁
    • 条件变量
    • 生产/消费者模型

    互斥锁

    mutex

    #include <iostream>
    #include<string>
    #include<thread>
    #include<mutex> 
    using namespace std;    
    
    mutex mtx;
    
    void print(int id, string name) {
        for (size_t i = 0; i < 10; i++)
        {
            mtx.lock();
            cout <<"我是 "<<id<<"号"<<"  ,我叫:"<<name<<endl;
            mtx.unlock();
            this_thread::sleep_for(chrono::seconds(1));// sleep 1s
        }
        
    }
    
    int main() {
        thread t1(print, 11, "lisi");
        thread t2(print, 22, "zhangsan");
        thread t3(print, 33, "lisi");
        thread t4(print, 44, "zhangsan");
        t1.join();
        t2.join();
        t3.join();
        t4.join();
        return 0;
    }
    

    **timed_mutex **

    timed_mutex tm_mtx;
    if (tm_mtx.try_lock()) //try_lock返回true表示加锁成功
    {
            /* code */
            tm_mtx.unlock();
    }
    
    timed_mutex tm_mtx;
    if (tm_mtx.try_lock_for(chrono::seconds(1))) //try_lock_for返回true表示加锁成功
    {
        /* code */
        tm_mtx.unlock();
    }
        
    

    recursive_mutex

    #include <iostream>
    #include<string>
    #include<thread>
    #include<mutex> 
    using namespace std;    
    
    class AA {
        private:
            recursive_mutex mtx; //递归锁
        public:
            void fun1() {
                mtx.lock();
                cout <<"fun1 runs.."<<endl;
                mtx.unlock();
            }
    
            void fun2() {
                mtx.lock();
                cout <<"fun1 runs.."<<endl;
                fun1(); // fun2调用fun1
                mtx.unlock();
            }
    };
    
    int main() {
        AA aa;
        aa.fun2();
        return 0;
    }
    

    生产者消费者模型

    #include <iostream>
    #include<string>
    #include<thread>
    #include<mutex> 
    #include<deque>
    #include<queue>
    #include<condition_variable>
    using namespace std;    
    
    class AA {
        mutex m_mutext; //互斥锁
        condition_variable m_cond; // 条件变量
        queue<string, deque<string>> m_q; // 缓存队列,底层容器用deque
    
        public:
            void incache(int num) { // 生产数据,num指定数据个数
                lock_guard<mutex> lock(m_mutext);//申请加锁
                for (size_t i = 0; i < num; i++)
                {
                    static int bh = 1; //物品编号
                    string message = to_string(bh++)+"号产品";
                    m_q.push(message); // 把生产出来的数据入队
                }
                m_cond.notify_one();//唤醒一个被当前条件变量阻塞的线程
            }
    
            void outcache() { // 消费者线程任务函数
                string message;
                while (true)
                {
                    // 把互斥锁换成unique_lock<mutex>,并申请加锁
                    unique_lock<mutex>lock(m_mutext);
    
                    while (m_q.empty())
                    {
                        m_cond.wait(lock);
                    }
    
                    // 数据元素出队
                    message = m_q.front(); 
                    m_q.pop();
                    cout <<"线程:"<<this_thread::get_id() <<"消费了,"<<message<<endl;
                    
                    this_thread::sleep_for(chrono::milliseconds(1));//假设数据处理需要1毫秒
                }
                
            }
    };
    
    int main() {
        AA aa;
    
        thread t1(&AA::outcache, &aa); // 创建消费者线程t1
        thread t2(&AA::outcache, &aa); // 创建消费者线程t2
        thread t3(&AA::outcache, &aa); // 创建消费者线程t3
    
        this_thread::sleep_for(chrono::seconds(2));//休眠2秒
        aa.incache(3); //生产3个数据
    
        this_thread::sleep_for(chrono::seconds(3));//休眠3秒
        aa.incache(5); // 生产5个数据
    
        t1.join();
        t2.join();
        t3.join();
        return 0;
    }
    

    原子类型atomic

    c11提供了atomic<T>模板类,用于支持原子类型,模板参数可以是bool,char,int,long,long long 指针类型(不支持浮点类型和自定义的 数据类型)

    #include <iostream>
    #include<atomic>
    #include<string>
    #include<thread>
    #include<mutex> 
    
    using namespace std;    
    
    atomic<int>num = 0;
    
    void fun() {
        for (size_t i = 0; i < 1000000; i++)
        {
            num++;
        } 
    }
    
    int main() {
        thread t1(fun);
        thread t2(fun);
        t1.join();
        t2.join();
    
        cout <<"num = "<<num<<endl;
        return 0;
    }
    
    int main() {
        atomic<int>a(33);
        cout <<"a = "<<a.load()<<endl;
        a.store(44); //把44存储到原子变量中。
        cout <<"a = "<<a.load()<<endl;
    
        int old; // 用于存放原值
        old = a.fetch_add(5); // 把原子变量a的值与5相加,返回原值
        cout <<"old = "<<old<<", a = "<<a.load()<<endl;
        old = a.fetch_add(2);
        cout <<"old = "<<old<<", a = "<<a.load()<<endl;
        return 0;
    }
    
    image.png
    int main() {
        atomic<int>a(33); // 原子变量
        int expected = 3; // 期待值
        int val = 5; // 打算存入原子变量的值
        /**
         * 比较原子变量的值和预期值expected
         * 如果两个值相等,把val存储到原子变量中
         * 如果两个值不相等,用原子变量的值更新预期值
         * 执行存储操作时,返回true,否则返回false
        */
        bool bret = a.compare_exchange_strong(expected, val);
        cout <<"bret = "<<bret<<endl;
        cout <<"a = "<<a<<endl;
        cout <<"expected = "<<expected<<endl;
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:c++线程

          本文链接:https://www.haomeiwen.com/subject/jzjnxdtx.html