zoukankan      html  css  js  c++  java
  • 详解c++多线程(一)

    c++的多线程可以充分利用计算机资源,提高代码运行效率。在这里总结了一些多线程应用过程中的基本概念和用法。

    一、进程与线程

    进程是资源分配和调度的一个独立单位。而线程是进程的一个实体,是CPU调度和分派的基本单位。

    一个进程至少拥有一个线程。

    在同一个进程中的多个线程的内存资源是共享的,也就是说各线程都可以改变进程中的变量。因此在执行多线程运算的时候要注意执行顺序。

    二、并发、并行的概念

    并行(parallellism)指的是多个任务在同一时刻同时在执行。

    而并发(concurrency)是指在一个时间段内,多个任务交替进行。虽然看起来像在同时执行,但其实是交替的。

    三、新建线程

    1)简单使用

    #include <iostream>
    #include <thread>
    
    using namespace std;
    
    void f()
    {
        cout<<"thread 1 is running"<<endl;
        this_thread::sleep_for(chrono::seconds(1));
    }
    
    int main()
    {
        thread t1(f); //创建线程,一旦创建完毕,马上开始运行。
        t1.join();
    }

    运行结果

    2)带函数参数的线程

     当需要向线程函数传递参数时,直接在创建线程时,同时也把参数作为入参传递给线程函数。注意当调用函数的参数为引用参数时,线程调用需要加上ref关键字表示引用。并且线程函数会改变引用的变量值。

    void f1(int n)
    {
        n++;
        cout<<"n = "<< n <<endl;
    }
    
    void f2(int &n)
    {
        n++;
        cout<<"n = "<<n<<endl;
    }
    
    int main()
    {
        int n = 0;
        
        thread t1(f1, n);
        t1.join();
        cout<<"n = "<<n<<endl;
        
        thread t2(f2, ref(n));
        t2.join();
        cout<<"n = "<<n<<endl;
    
    }

      运行结果为:

    3)替换线程

    void f2(int &n)
    {
        n++;
        cout<<"n = "<<n<<endl;
    }
    
    int main()
    {
        int n = 0;
        
        thread t3(f2, ref(n));
        thread t4(move(t3)); //此时t4正在运行f2(),t3不再是一个线程了。
        t4.join();
    
    }

    运行结果:

    4)调用类成员函数

    class foo
    {
    public:
        void bar1(int n)
        {
            cout<<"n = "<<n<<endl;
        }
        static void bar2(int n)
        {
            cout<<"static function is running"<<endl;
            cout<<"n = "<<n<<endl;
        }
    };
    
    int main()
    {
        foo f;
        thread t1(&foo::bar1, &f, 5); //注意在调用非静态类成员函数时,需要加上实例变量。
        t1.join();
        
        thread t2(&foo::bar2, 4);
        t2.join();
    }

    四、线程操作

    1) join

    join的意思就是等待子进程完成,再继续主进程。即使线程在调用join前已经执行完毕,join也是有用的。

    void f1(int n)
    {
        cout<<"thread "<<n<<" is running"<<endl;
    }
    
    
    int main()
    {
        thread t1(f1, 1); //开始运行线程t1
        thread t2(f1, 2); //开始运行线程t2
        thread t3(f1, 3); //开始运行线程t3
        
        t1.join(); //等待线程t1执行完毕
        t2.join(); //等待线程t2执行完毕
        t3.join(); //等待线程t3执行完毕
    }

    注意用多个线程同时启动后,实际是并发执行。由cpu的控制台来决定当前调用哪个线程。所以实际运行过程可能会多次交替,线程1 - 线程2 - 线程1 - 线程3 - 线程1.....所以得到的结果是混乱的。

     而每次运行的结果都可能都不一样。

    第一次运行结果:

    第二次运行结果: 

    假如需要在运行线程t2之前,结果t1,那么就可以在t2之前,执行t1.join()。

    void f1(int n)
    {
        cout<<"thread "<<n<<" is running"<<endl;
    }
    
    
    int main()
    {
        thread t1(f1, 1); //开始运行线程t1
        t1.join(); //等待线程t1执行完毕
        
        thread t2(f1, 2); //开始运行线程t2
        thread t3(f1, 3); //开始运行线程t3
        
        t2.join(); //等待线程t2执行完毕
        t3.join(); //等待线程t3执行完毕
    }

    运行结果:

    2)detach

    detach操作可以将线程分离,允许线程独立执行。等到线程执行完毕后,系统会自动将资源回收。

    void independentThread()
    {
        cout<<"start concurrent thread"<<endl;
        cout<<"Exiting concurrent thread"<<endl;
    }
    
    void threadCaller()
    {
        cout<<"Start thread caller"<<endl;
        thread t(independentThread);
        t.detach(); //将线程分离
        cout<<"Exiting thread caller"<<endl;
    }
    
    int main()
    {
        threadCaller();
    }

    注意:每个线程要么detach,独立运行,然后系统自动回收资源;要么join,也就是让主线程等待子线程结束之后,主线程将资源回收。

    如果两个操作都不执行,可能会出现内存泄漏。

    3)线程暂停

    如果让线程从外部暂停会引发很多并发问题,这也是为什么std::thread没有直接提供pause函数的原因。如果线程在运行过程中,确实需要停顿,就可以用this_thread::sleep_for。

    void threadCaller()
    {
        this_thread::sleep_for(chrono::seconds(3)); //此处线程停顿3秒。
        cout<<"thread pause for 3 seconds"<<endl;
    }
    
    int main()
    {
        thread t(threadCaller);
        t.join();
    }

    4)获取当前线程号

    int main()
    {
        thread::id main_threadId =  this_thread::get_id();
        cout<<main_threadId<<endl;
    }

    运行结果: 

    参考:https://www.jianshu.com/p/dcce068ee32b

       https://en.cppreference.com/w/cpp/thread/thread

  • 相关阅读:
    sql
    vs 2010创建Windows服务定时timer程序
    C#(.net)实现用apache activemq传递SQLite的数据
    ASP.net与SQLite数据库通过js和ashx交互(连接和操作)
    Object
    Thread
    多线程知识
    HTTPS详解
    TCP协议
    [BJDCTF 2nd]假猪套天下第一 && [BJDCTF2020]Easy MD5
  • 原文地址:https://www.cnblogs.com/corineru/p/10847394.html
Copyright © 2011-2022 走看看