千家信息网

如何理解C++多线程编程

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,这篇文章主要讲解了"如何理解C++多线程编程",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何理解C++多线程编程"吧!目录C++多线程1. 概念1.
千家信息网最后更新 2026年11月01日如何理解C++多线程编程

这篇文章主要讲解了"如何理解C++多线程编程",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何理解C++多线程编程"吧!

目录
  • C++多线程

  • 1. 概念

    • 1.1 概念

  • 2. 常用API

    • 1.thread

    • 2.互斥锁mutex

    • 3. 挂起和唤醒

  • 3. 应用场景

    • 3.1 call_once执行一次的函数

    • 3.2 condition_variable条件锁

    • 3.3 future获取线程的计算结果

    • 3.4 promise主线程如何将数据发送数据到其他线程

    • 3.5 future.share()多线程之间共享状态

    • 3.6 线程packaged_task

    • 3.7 时间约束

  • 4. Windows多线程

    • 4.1 Windows创建线程

    • 4.2 Windows互斥锁

    • 4.3 Windows挂起和唤醒线程

  • 总结

C++多线程

1. 概念

1.1 概念

  • 进程:一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。

  • 线程:进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。

  • 并发:并发指的是两个或多个独立的活动在同一时段内发生。并发在生活中随处可见:比如在跑步的时候同时听音乐,在看电脑显示器的同时敲击键盘等。同一时间段内可以交替处理多个操作,强调同一时段内交替发生。

  • 并行:同一时刻内同时处理多个操作,强调同一时刻点同时发生。

2. 常用API

头文件#include

1.thread

API描述注意
thread.join()加入线程(会阻塞主线程,模拟同步操作)
thread.detach()加入线程(不会阻塞主线程,模拟异步操作)
thread.joinable()是否可加入线程,返回bool
thread.get_id()获取线程的ID
thread.hardware_concurrency()获取硬件并发的数量
thread.swap()交换线程
thread.native_handle()获取原生handle,为windows多线程中CreateThread的返回值,使用这个handle从而可以实现线程的挂起唤醒

测试代码:

void threadFunc01() {        cout << "thread join1" << endl;        this_thread::sleep_for(chrono::seconds(2));}void threadFunc02() {        cout << "thread join2" << endl;        this_thread::sleep_for(chrono::seconds(2));}void test01() {        // 创建线程        std::thread thread1(threadFunc01);        std::thread thread2(threadFunc02);        //thread.join(); //join 会阻塞主线程 同步操作        //thread.detach(); //detach 不会阻塞主线程 异步操作        bool bJoinAble = thread1.joinable();        thread::id threadId = thread1.get_id();        //hardware_concurrency 硬件并发的数量        int threadNum = thread1.hardware_concurrency();        cout << "hardware_concurrency:" << threadNum << endl;        //应用 线程的预分配。        for (int i = 0; i < thread1.hardware_concurrency(); i++) {                std::thread threadRef(threadFunc01);                threadRef.detach();        }        thread1.swap(thread2);        thread1.join();}

向线程里传递参数的方法:

// 向线程里传递参数的方法#includevoid threadFunc03(int num, const string& str) {        cout << "num = " << num << " str = " << str << endl;}struct FObject {        void Run(const string& str) {                cout << str << endl;        }};void test02() {    // 通过函数绑定        thread newThread1(threadFunc03, 10, "Unreal");        newThread1.detach();        // 通过lambda绑定        int a = 50;        thread newThread2([&](int num,const string& str) {                cout << "a = " << a << " num = " << num << " str = " << str << endl;                }, 1, "Unreal");        newThread2.detach();        // 绑定对象        FObject objectRef;        thread newThread3(&FObject::Run, objectRef, "Unreal");        newThread3.detach();}

2.互斥锁mutex

头文件#include

API描述注意
mutex.lock()上锁
mutex.unlock()解锁
mutex.try_lock()判断可不可以加锁,返回bool可以用该方法建立非阻塞模式

测试代码:

#includemutex lockRef;void threadFunc04(int num,const string& str) {        // 进入该线程锁住该线程,其他线程想要进入该线程需要排队        lockRef.lock();        cout << "thread join4" << endl;        this_thread::sleep_for(chrono::seconds(2));        // 解锁        lockRef.unlock();}void test03() {        std::thread thread1(threadFunc04, 10, "Unreal");        std::thread thread2(threadFunc04, 5, "Unity");        std::thread thread3(threadFunc04, 20, "Cocos");        thread1.detach();        thread2.detach();        thread3.detach();}

使用类加锁的方式:

#includemutex lockRef;struct FEvent {        FEvent() {                m.lock();        }        ~FEvent()        {                m.unlock();        }        static mutex m;};mutex FEvent::m;#define LOCK_SCOPE FEvent Eventvoid threadFunc04(int num,const string& str) {        LOCK_SCOPE; //加上锁,并且过了这个作用域自动解锁(析构)        cout << "thread join4" << endl;        this_thread::sleep_for(chrono::seconds(2));}void test03() {        std::thread thread1(threadFunc04, 10, "Unreal");        std::thread thread2(threadFunc04, 5, "Unity");        std::thread thread3(threadFunc04, 20, "Cocos");        thread1.detach();        thread2.detach();        thread3.detach();}

try_lock()

void threadFunc04(int num,const string& str) {        bool bLock = FEvent::m.try_lock();        if (bLock) {                LOCK_SCOPE; //加上锁,并且过了这个作用域自动解锁(析构)                cout << "thread join4" << endl;                this_thread::sleep_for(chrono::seconds(2));        }}

使用try_lock()可以进行判断能不能上锁,不能上锁的话,就不用执行上锁后的代码,防止其他线程阻塞在该线程。

lock_guard

lock_guard是一种锁类,作用和我们上面自定义的锁类FEvent相同,创建的时候锁住目标线程,释放的时候解锁。

// 声明方式lock_guardref;

源码:

template class lock_guard { // class with destructor that unlocks a mutexpublic:    using mutex_type = _Mutex;    explicit lock_guard(_Mutex& _Mtx) : _MyMutex(_Mtx) { // construct and lock        _MyMutex.lock();    }    lock_guard(_Mutex& _Mtx, adopt_lock_t) : _MyMutex(_Mtx) { // construct but don't lock    }    ~lock_guard() noexcept {        _MyMutex.unlock();    }    lock_guard(const lock_guard&) = delete;    lock_guard& operator=(const lock_guard&) = delete;private:    _Mutex& _MyMutex;};

unique_lock

作用和lock_guard相同,唯一的不同之处,lock_guard开放的API只有析构函数,而unique_lock开放的API非常多,即自由度比lock_guard高,可以定义锁的行为。

void test05() {        // defer_lock 关键字为延迟锁,即创建该对象时不会锁住该线程,什么时候锁需要自定义        std::unique_locklockRef2(FEvent::m,defer_lock);        std::unique_locklockRef2(FEvent::m,chrono::seconds(2)); //锁两秒        //....执行        lockRef2.lock();        lockRef2.unlock();        bool bLock1 = lockRef2.try_lock();//尝试上锁        lockRef2.try_lock_for(chrono::seconds(2)); //锁2s    mutex *lockRef3 = lockRef2.release(); //释放锁,同时会返回被释放的这个锁的指针对象    bool bLock2 = lockRef2.owns_lock(); //当前是否被锁住 }

应用:

void test05() {        //std::lock_guardlockRef1(FEvent::m);        // defer_lock 关键字为延迟锁        std::unique_locklockRef2(FEvent::m,defer_lock);        lockRef2.lock();        lockRef2.mutex();        bool bLock = lockRef2.owns_lock();        std::unique_locklockRef3;        lockRef2.swap(lockRef3);        std::unique_locklockRef4 = move(lockRef3);        lockRef4.unlock();}

3. 挂起和唤醒

头文件#include

API描述注意
SuspendThread(thread.native_hadle())挂起线程
ResumeThread(thread.native_hadle())唤醒线程
Sleep()睡眠

测试代码:

#includevoid threadFunc05() {        while (true)        {                Sleep(10);                cout << "threadFunc05" << endl;        }}void test04() {        thread thread1(threadFunc05);        // 挂起线程        SuspendThread(thread1.native_handle());        Sleep(2);        // 唤醒线程        ResumeThread(thread1.native_handle());}

如何高效将主线程资源进行转移:

void threadFunc06(const char* str) {        cout << str << endl;}void test04() {        // 如何高效转移线程资源        // 使用std::move        thread thread2(threadFunc06, move("Unreal")); // 使用move避免了拷贝        thread thread3 = move(thread2);        thread3.detach();}

3. 应用场景

3.1 call_once执行一次的函数

通过使用该函数,用来防止多线程的多次触发。

once_flag tag;void callonceTest() {        call_once(tag, [&]() {                cout << "Do once" << endl;                });}void test06() {        for (int i = 0; i < 10; i++) {                thread thread1(callonceTest);                thread1.detach();        }}

3.2 condition_variable条件锁

使用需要包含头文件#include

可以使用条件锁来达到同步的作用,即当满足一定的条件后才解锁某个线程。

#includecondition_variable condition_lock;mutex mutexLock;void conditionFuncTest() {        unique_locklock(mutexLock);        condition_lock.wait(lock);  //锁住该线程        cout << "Run" << endl;}void test12() {        std::thread threadRef(conditionFuncTest);        threadRef.detach();        Sleep(3000); //3s后再激活        condition_lock.notify_one();}

3.3 future获取线程的计算结果

通过使用future可以得到"未来"线程被调用的时候计算得返回值,使用时需要包含头文件#include。

声明方式:

// async为创建该线程的方式为异步 funName 函数名 args为传入的函数参数std::futurenewFuture = std::async(launch::async, funName,args...);

应用:

#include string getString(int num) {        return "Unreal";}void test08() {        std::futurenewFuture = std::async(launch::async, getString, 10);        //std::futurenewFuture = std::async(launch::deferred, getString, 10); // 睡一秒再执行        Sleep(1000);        string str = newFuture.get(); //get只能调用一次 调第二次会崩溃        // 防止崩溃的写法        if (newFuture.valid()) {                string str = newFuture.get();        }}

3.4 promise主线程如何将数据发送数据到其他线程

通过使用promise(承诺)来进行进程之间的交互,常配合std::future使用。其作用是在一个线程t1中保存一个类型typename T的值,可供相绑定的std::future对象在另一线程t2中获取。

测试代码:

// promisestring promiseTest(future& future) {        cout << future.get() << endl;        return "Unreal";}void test09() {        promise promiseRef;        futurefuture1 = promiseRef.get_future();        futurefuture2 = std::async(launch::async, promiseTest, std::ref(future1)); //future 不支持值拷贝 需要传递引用        promiseRef.set_value("Unreal is the best game engine in the world");}

但这里也有一个问题需要思考,如果需要发送数据到多个线程,是不是需要一个个的创建上面的代码呢。这里就引出了多线程之间共享状态这个解决方法。

3.5 future.share()多线程之间共享状态

通过future.share()我们可以很方便的使多个线程之间共享状态。

现在来看看没有使用该函数的话我们要共享状态的话需要这么写:

string promiseTest(future& future) {        cout << future.get() << endl;        return "Unreal";}void test09() {        promise promiseRef;        futurefuture1 = promiseRef.get_future();        futurefuture2 = promiseRef.get_future();        futurefuture3 = promiseRef.get_future();        futurefuture4 = std::async(launch::async, promiseTest, std::ref(future1)); //future 不支持值拷贝 需要传递引用        futurefuture5 = std::async(launch::async, promiseTest, std::ref(future2)); //future 不支持值拷贝 需要传递引用        futurefuture6 = std::async(launch::async, promiseTest, std::ref(future3)); //future 不支持值拷贝 需要传递引用        promiseRef.set_value("Unreal is the best game engine in the world");}

使用了future.share()函数后:

string promiseTest02(shared_future future) {        cout << future.get() << endl;        return "Unreal";}void test09() {        promise promiseRef;        futurefuture1 = promiseRef.get_future();    // shared_future        shared_future sharedFutrue1 = future1.share();        futurefuture2 = std::async(launch::async, promiseTest02, sharedFutrue1); //shared_future 可以用拷贝传递        futurefuture3 = std::async(launch::async, promiseTest02, sharedFutrue1);        futurefuture4 = std::async(launch::async, promiseTest02, sharedFutrue1);        promiseRef.set_value("Unreal is the best game engine in the world");}

3.6 线程packaged_task

packaged_task和promise非常相似,packaged_task是对promise>中T= std::function这一可调对象(如函数、lambda表达式等)进行了包装,简化了使用方法。并将这一可调对象的返回结果传递给关联的future对象。

绑定Lambda

void test10() {        //绑定lambda        packaged_task task1([](int a,int b) ->int{                return a + b;                });        task1(1, 4);        this_thread::sleep_for(chrono::seconds(1));        if (task1.valid()) {                auto f1 = task1.get_future();                cout << f1.get() << endl;        }}

绑定普通函数

int packagedTest(int a,int b) {        return a + b;}void test10() {        //绑定函数        packaged_tasktask2(packagedTest);        task2(10, 5);        this_thread::sleep_for(chrono::seconds(1));        if (task2.valid()) {                auto f2 = task2.get_future();                cout << f2.get() << endl;        }}

使用std::bind进行函数绑定

int packagedTest(int a,int b) {        return a + b;}void test10() {        // bind        packaged_tasktask3(std::bind(packagedTest,1,2));        task3(10, 5); //因为bind使用了占位符 所以这里传入的10 5失效了        this_thread::sleep_for(chrono::seconds(1));        if (task3.valid()) {                auto f3 = task3.get_future();                cout << f3.get() << endl; //1+2        }}

3.7 时间约束

void test11() {        //休眠2s        this_thread::sleep_for(chrono::seconds(2));        // 休眠现在的时间加上2s        chrono::steady_clock::time_point timePos = chrono::steady_clock::now() + chrono::seconds(2);        this_thread::sleep_until(timePos);}

4. Windows多线程

使用WindowsAPI进行多线程的编写,需要包含头文件

#include

4.1 Windows创建线程

使用CreateThread()创建线程

DWORD WINAPI funcThread(LPVOID lpPram) {    // DWORD 类型为unsigned long    // LPVOID 类型为void    cout << "Unreal!" << endl;    Sleep(1000);    return 0l;}void windowsThreadTest01() {        HANDLE handleRef = CreateThread(nullptr,0, funcThread,nullptr,0,nullptr);    Sleep(2000);    CloseHandle(handleRef); //使用之后需要关闭handle}

其中传入的参数为:

/*WINBASEAPI_Ret_maybenull_HANDLEWINAPICreateThread(    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,  和线程安全有关 一般为null    _In_ SIZE_T dwStackSize,                            线程栈的大小    _In_ LPTHREAD_START_ROUTINE lpStartAddress,         被线程执行的回调函数    _In_opt_ __drv_aliasesMem LPVOID lpParameter,       传入线程的参数    _In_ DWORD dwCreationFlags,                         创建线程的标志   参数0 代表立即启动该线程    _Out_opt_ LPDWORD lpThreadId                        传出的线程ID);*/

4.2 Windows互斥锁

// windows互斥锁HANDLE hMutex = nullptr;DWORD WINAPI funcThread02(LPVOID lpParam) {    cout << "Unreal" << endl;    WaitForSingleObject(hMutex, INFINITE);    Sleep(5000);    ReleaseMutex(hMutex);    return 0l;}void windowsThreadTest02() {    hMutex = CreateMutex(nullptr, false, L"Mutex");    HANDLE handleRef1 = CreateThread(nullptr, 0, funcThread02, nullptr, 0, nullptr);    HANDLE handleRef2 = CreateThread(nullptr, 0, funcThread02, nullptr, 0, nullptr);    CloseHandle(handleRef1);    CloseHandle(handleRef2);}

传入的参数为:

/*WINBASEAPI_Ret_maybenull_HANDLEWINAPICreateMutexW(    _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,      和线程安全有关一般为null    _In_ BOOL bInitialOwner,                               有没有该锁的控制权    _In_opt_ LPCWSTR lpName                                锁名字    );*/

4.3 Windows挂起和唤醒线程

通过使用SuspendThread(HandleRef)和ResumeThread(HandleRef)来挂起和唤醒线程

// windows 挂起唤醒DWORD WINAPI funcThread03(LPVOID lpParam) {    while (true) {        Sleep(500);        cout << "IsRunning" << endl;    }    return 0l;}void windowsThreadTest03() {    HANDLE hRef = CreateThread(nullptr, 0, funcThread03, nullptr, 0, nullptr);    SuspendThread(hRef);    Sleep(2000);    ResumeThread(hRef);    CloseHandle(hRef);}

感谢各位的阅读,以上就是"如何理解C++多线程编程"的内容了,经过本文的学习后,相信大家对如何理解C++多线程编程这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

0