C++创建线程

std::thread 是 C++11 引入的标准库中的线程支持类,它允许你创建、控制和同步线程。

一、创建线程的方法

1.下述示例中,std::thread构造函数接受一个可调用对象(这里是一个函数myFunction),然后创建一个新线程并开始执行这个可调用对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <thread>
 
void myFunction() {
    std::cout << "Hello from thread!\n";
}
 
int main() {
    // 创建一个新线程并执行 myFunction()
    std::thread myThread(myFunction);
 
    // 主线程执行自己的任务
    std::cout << "Hello from main!\n";
 
    // 等待子线程执行完毕
    myThread.join();
 
    return 0;
}

输出结果:  

2.在下面的示例中,printMessage函数接受一个const std::string&类型的参数,然后将这个参数传递给std::thread构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <thread>
 
void printMessage(const std::string& message) {
    std::cout << message << std::endl;
}
 
int main() {
    std::string msg = "Hello from thread!";
    std::thread myThread(printMessage, msg);
 
    // 主线程执行自己的任务
    std::cout << "Hello from main!\n";
 
    myThread.join();
 
    return 0;
}

输出结果:

3.使用Lambda表达式,Lambda 表达式允许你在创建线程时内联定义线程函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <thread>
 
int main() {
    int x = 42;
 
    // 使用 Lambda 表达式创建线程
    std::thread myThread([&x] {
        std::cout << "Value of x: " << x << std::endl;
        });
 
    // 主线程执行自己的任务
    std::cout << "Hello from main!\n";
 
    myThread.join();
 
    return 0;
}

输出结果:  

4.使用detach分离线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <thread>
 
void myFunction() {
    std::cout << "Hello from thread!\n";
}
 
int main() {
    std::thread myThread(myFunction);
 
    // 分离线程,使其在后台运行
    myThread.detach();
 
    // 主线程执行自己的任务
    std::cout << "Hello from main!\n";
 
    // 注意:分离的线程在主线程结束时可能还未执行完毕
 
    return 0;
}

输出结果:

二、创建线程示例

复制代码
#include <iostream>
#include <thread>
#include <mutex>

/* 函数指针创建线程 */
void thread_func(int size) {
    std::cout << "thread_func:" << std::this_thread::get_id() << std::endl;
    
    for (size_t i = 0; i < size; ++i) {
        std::cout << "display form thread:" << std::endl;
    }
}

/* 仿函数创建线程 */
class DisplayThread {
public:
    void operator()() {
        std::cout << "DisplayThread:" << std::this_thread::get_id() << std::endl;
        for (size_t i = 0; i < 10; ++i) {
            std::cout << "display form display:" << std::endl;
        }
    }
};

int main() {
    /* 获取线程ID */
    std::cout << "main:" << std::this_thread::get_id() << std::endl;
    std::thread thread_1(thread_func, 10);
    for (size_t i = 0; i < 10; ++i) {
        std::cout << "display form main_1:" << std::endl;
    }
    /* 阻塞等待线程结束 */
    thread_1.join();

    std::thread thread_2((DisplayThread()));
    /* 线程后台执行,非阻塞 */
    thread_2.detach();


    /* Lambda函数创建线程 */
    std::thread thread_3(
        [] {
            std::cout << "thread_3:" << std::this_thread::get_id() << std::endl;
            for (size_t i = 0; i < 5; ++i) {
                std::cout << "display form thread_3:" << std::endl;
            }
        }
    );

    for (size_t i = 0; i < 5; ++i) {
        std::cout << "display form main_2:" << std::endl;
    }
    thread_3.join();

    system("pause");

    return 0;
}
复制代码

三、互斥锁的使用

复制代码
#include <iostream>
#include <thread>
#include <mutex>

void thread_work_1(int& sum) {
    for (size_t i = 1; i < 5000; ++i) {
        sum += i;
    }
}

void thread_work_2(int& sum) {
    for (size_t i = 5000; i <= 10000; ++i) {
        sum += i;
    }
}

int main_func() {
    int sum = 0;
    for (size_t i = 1; i <= 10000; ++i) {
        sum += i;
    }

    return sum;
}

int main() {
    
    int sum = 0;
    std::thread t1(thread_work_1, std::ref(sum));
    std::thread t2(thread_work_2, std::ref(sum));
    t1.join();
    t2.join();
    std::cout << "thread sum:" << sum << std::endl;
    std::cout << "main func sum:" << main_func() << std::endl;

    system("pause");

    return 0;
}
复制代码

上述代码是求1-10000的和,我们为了提高效率,创建了两个线程同时去计算[1,5000)的和以及[5000,10001)的和,那么用于计算和的变量都用相同的ans来获取结果。为了区别多线程的计算结果,在主线程中调用main_func函数求的结果与其作比较。

我们发现两次的运算结果并不相同,那么我们可以分析一下原因,因为在计算过程中的sum是一个引用,是他们的共享资源,所以当一个线程正在计算+i的时候,此时还没有运算结束,就被切到了另一个线程中,然后在这个线程中可能会计算了很多次+i的操作,然后再切回那个线程中时,计算结果可能就会覆盖掉另一个线程的计算结果,因此这样求出来的数一定是比正确结果要小的,所以为了避免这种情况的发生,引入了互斥锁。互斥锁的重点在于他是一个锁,简单来说就是我们用锁将两个线程中计算过程分别用mutex锁上,那么当一个线程正在计算的时候,另一个线程就会等待这个计算的完成。大致流程是这样的,当work1准备计算sum+=i的时候,用mutex将线程其锁上,如果此时sum+=i还没有计算完就切到了work2的线程时,就会通过mutex检测到已经被锁上了,那么work2就会在此等待work1的计算完成,当work1的计算完成以后就会把锁解开,然后进行下一步的计算。所以两个线程种的计算过程都是加锁-计算-解锁的过程,这样就不会出现上述所说的那种情况了。

复制代码
#include <iostream>
#include <thread>
#include <mutex>

void thread_work_1(int& sum, std::mutex& mtx_lock) {
    for (size_t i = 1; i < 5000; ++i) {
        mtx_lock.lock();
        sum += i;
        mtx_lock.unlock();
    }
}

void thread_work_2(int& sum, std::mutex& mtx_lock) {
    for (size_t i = 5000; i <= 10000; ++i) {
        mtx_lock.lock();
        sum += i;
        mtx_lock.unlock();
    }
}

int main_func() {
    int sum = 0;
    for (size_t i = 1; i <= 10000; ++i) {
        sum += i;
    }

    return sum;
}

int main() {
    std::mutex mtx_lock;
    int sum = 0;
    std::thread t1(thread_work_1, std::ref(sum), std::ref(mtx_lock));
    std::thread t2(thread_work_2, std::ref(sum), std::ref(mtx_lock));
    t1.join();
    t2.join();
    std::cout << "thread sum:" << sum << std::endl;
    std::cout << "main func sum:" << main_func() << std::endl;

    system("pause");

    return 0;
}
复制代码

还有一种是用lock_guard类模板,它的内部结构很简单,只有构造函数和析构函数,所以也很容里理解它的工作原理,在实例化对象时通过构造函数实现了lock,在析构函数中实现了unlock的操作。这样就可以避免忘记unlock的情况,具体的实现看下面的代码:

复制代码
#include <iostream>
#include <thread>
#include <mutex>

void thread_work_1(int& sum, std::mutex& mtx_lock) {
    for (size_t i = 1; i < 5000; ++i) {
        std::lock_guard<std::mutex> mtx_guard(mtx_lock);
        sum += i;
    }
}

void thread_work_2(int& sum, std::mutex& mtx_lock) {
    for (size_t i = 5000; i <= 10000; ++i) {
        std::lock_guard<std::mutex> mtx_guard(mtx_lock);
        sum += i;
    }
}

int main_func() {
    int sum = 0;
    for (size_t i = 1; i <= 10000; ++i) {
        sum += i;
    }

    return sum;
}

int main() {
    std::mutex mtx_lock;
    int sum = 0;
    std::thread t1(thread_work_1, std::ref(sum), std::ref(mtx_lock));
    std::thread t2(thread_work_2, std::ref(sum), std::ref(mtx_lock));
    t1.join();
    t2.join();
    std::cout << "thread sum:" << sum << std::endl;
    std::cout << "main func sum:" << main_func() << std::endl;

    system("pause");

    return 0;
}
复制代码

 

posted @   TechNomad  阅读(811)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
历史上的今天:
2019-04-11 转:如何上传自己的项目到github呢?
点击右上角即可分享
微信分享提示