c++ 多线程编程demo

c++ 多线程编程demo

最佳实践:(摘录《c++高级编程 27.13 线程设计和最佳实践》)

  1. 使用并行标准库算法
  2. 终止应用程序前,确保所有thread对象都不是可joinable的
  3. 最好的同步就是没有同步(各线程只读取共享数据,不写入)
  4. 尝试使用单线程的所有权模式(一个线程拥有数据的独有权,处理完再传递给另一个线程)
  5. 在可能时使用原子类型和操作
  6. 使用锁保护可变的共享数据
  7. 尽快释放锁
  8. 不要手动获取多个锁,应该使用std::lock或std::try_lock(获取多个锁顺序要一致)
  9. 使用多线程的分析器
  10. 使用RAII锁对象(lock_guard、unique_loce、shared_lock、scoped_lock)
  11. 了解调试器的对线程支持特性
  12. 使用线程池,不动态创建和销毁大量线程
  13. 使用高级线程库(TBB、PPL)

I/O多路复用
https://zhuanlan.zhihu.com/p/115220699

几个多线程常用demo代码:

#include <atomic>
#include <latch>
#include <barrier>
#include <semaphore>
#include <future>
#include <iostream>
#include <thread>
#include <chrono>

using namespace std::chrono_literals;

void counter(int id, int numIterations)
{
    for (int i{ 0 }; i < numIterations; i++) {
        std::cout << "Counter " << id << " has value " << i << std::endl;
    }
}

void increment(std::atomic<int>& counter)
{
    for (int i{ 0 }; i < 100; i++) {
        ++counter;
        std::this_thread::sleep_for(std::chrono::microseconds(1));
    }
}

void increment_ref(int& counter)
{
    std::atomic_ref<int> atomicCounter{ counter };
    for (int i{ 0 }; i < 100; i++) {
        ++atomicCounter;
        std::this_thread::sleep_for(std::chrono::microseconds(1));
    }
}

class Counter
{
public:
    Counter(int id, int numIterations) :m_id{ id }, m_numIterations{ numIterations } {}

    void operator()() const noexcept
    {
        for (int i{ 0 }; i < m_numIterations; ++i) {
            std::lock_guard lock{ ms_mutex };
            std::cout << "Counter " << m_id << " has value " << i << std::endl;
        }
    }

    void process() {
        for (int i{ 0 }; i < m_numIterations; ++i) {
            std::unique_lock lock{ ms_timed_mutex ,200ms };
            if (lock) {
                std::cout << "Counter " << m_id << " has value " << i << std::endl;
            }
        }
    }

private:
    int m_id;
    int m_numIterations;
    inline static std::mutex ms_mutex;
    inline static std::timed_mutex ms_timed_mutex;
};

int k;
thread_local int n;

void counter_k(int id)
{
    std::cout << std::format("Thread {}:k={},n={}\n ",id, k,n);
    ++k;
    ++n;
    std::cout << std::format("Thread {}:k={},n={}\n ", id, k, n);
}

void doSomeWork()
{
    throw std::runtime_error{" Exception from thread"};
}

void threadFunc(std::exception_ptr& err)
{
    try {
        doSomeWork();
    }
    catch (...) {
        err = std::current_exception();
    }
}

void doWorkInThread()
{
    std::exception_ptr error;
    std::thread te{ threadFunc,std::ref(error) };
    te.join();
    if (error) {
        std::rethrow_exception(error);
    }
}

int main()
{
    std::cout.sync_with_stdio(false);
    std::thread t1{ counter, 1, 6 };
    std::thread t2{ counter, 2, 4 };
    t1.join();
    t2.join();

    std::thread t3{ Counter{3, 10} };
    t3.join();

    Counter c{ 4, 5 };
    std::thread t4{ std::ref(c) };
    t4.join();

    int id{ 5 };
    int numIterations{ 6 };
    std::thread t5{ [id, numIterations]() {
        for (int i{ 0 }; i < numIterations; ++i) {
            std::cout << "Counter " << id << " has value " << i << std::endl;
        }
    } };
    t5.join();

    Counter c1{ 6, 5 };
    std::thread t6{ &Counter::process,&c1 };
    t6.join();

    std::thread t11{ counter_k ,1};
    t11.join();
    std::thread t12{ counter_k ,2};
    t12.join();

    // jthread c++20 ,destory finish join
    std::jthread job{ [](std::stop_token token) {
        while (!token.stop_requested()) {
            std::cout << "running\n";
            Sleep(100);
        }
    }
    };
    Sleep(1000);
    job.request_stop();
    std::cout << "stop running\n";

    // catch error from thread
    try {
        doWorkInThread();
    }
    catch (const std::exception& e) {
        std::cout << "Main thread caught:" << e.what()<< std::endl;
    }
    // atomic
    std::atomic<int> counter{ 0 };
    int con{0};
    std::vector<std::thread> threads;
    for (int i{ 0 }; i < 10; ++i) {
        threads.push_back(std::thread{ increment,std::ref(counter) });
        threads.push_back(std::thread{ increment_ref,std::ref(con) });
    }
    
    for (auto& t : threads) {
        t.join();
    }
    std::cout << "Result:" << counter << std::endl;
    std::cout << "Result:" << con << std::endl;

    std::atomic<int> value{0};
    std::thread job1{ [&value]() {
        std::cout << "wait value:" << value << std::endl;
        value.wait(value);
        std::cout << "value:" << value << std::endl;
    } };

    std::this_thread::sleep_for(std::chrono::seconds(2));

    value = 1;
    value.notify_all();

    job1.join();

    // 同步控制 latch
    std::latch startlatch{10};
    std::vector<std::jthread> threads_;
    for (int i{ 0 }; i < 10;i++) {
        threads_.push_back(std::jthread{ [&startlatch, id = i]() {
                std::this_thread::sleep_for(20ms);
                std::cout << "latch:" << id << std::endl;
                startlatch.count_down();

                startlatch.wait();
                std::cout << "latch:finish" << id << std::endl;
            }});
    }
    startlatch.wait();
    std::cout << "latch:finish";
    threads_.clear();

    // 同步控制 latch
    const auto workers = { "anil", "busara", "carl" };
    auto on_completion = []() noexcept {
        static const char* phase = "... done\n" \
            "Cleaning up...\n";
        std::cout << phase;
        phase = "... done\n";
    };
    std::barrier sync_point(workers.size(),on_completion);
    auto work = [&](const std::string& name) {
        std::string product = "  " + name + " worked\n";
        std::cout << product; // ok, op<< call is atomic
        sync_point.arrive_and_wait();
        product = "  " + name + " cleaned\n";
        std::cout << product;
        sync_point.arrive_and_wait();
    };

    std::cout << "Starting...\n";
    for (auto const& worker : workers) {
        threads_.push_back(std::jthread{ work,worker });
    }

    // semaphore
    threads_.clear();
    std::counting_semaphore sp{4};
    for (int i{ 0 }; i < 20; i++) {
        threads_.push_back(std::jthread{ [&sp,id = i]() {
            sp.acquire();
            std::cout << "thread..."<< id << "\n";
            std::this_thread::sleep_for(100ms);
            sp.release();
            }
            });
    }

    // future and promise
    std::promise<int> m_;
    std::future<int> theFuture{m_.get_future()};
    std::thread t{ [](std::promise<int> p) { p.set_value(12); }, std::move(m_) };
    auto va = theFuture.get();
    std::cout << "the future value:" << va << std::endl;
    t.join();
  
    // 条件变量
    std::mutex m_mu;
    std::unique_lock<std::mutex> lock(m_mu);
    std::condition_variable con_var;
    std::atomic<int> ca{0};
    std::async(std::launch::async, [&ca]() {
        std::cout << "thread the value in: \n";
        std::this_thread::sleep_for(3s);
        std::cout << "change the value end: \n";
        ca = 5;
        });
    std::cout << "wait the value: \n";
    con_var.wait(lock, [&ca]() { return (ca > 0); });
    std::cout << "wait the value finish:" << ca << std::endl;

    // packaged_task
    std::packaged_task task{ []() { return 12; } };
    std::future fur{ task.get_future() };
    std::thread tt{std::move(task)};
    auto re = fur.get();
    std::cout << "wait the task value:" << re << std::endl;
    tt.join();

    // shared_future
    std::promise<void> tP1, tP2;
    std::promise<int> signalP;
    std::shared_future<int> sf{ signalP.get_future().share() };
    auto fun1 = [&tP1, sf]() {
        tP1.set_value();
        auto p{sf.get()};
        std::cout << "thread1 get value:" << p << std::endl;
    };
    auto fun2 = [&tP2, sf]() {
        tP2.set_value();
        auto p{ sf.get() };
        std::cout << "thread1 get value:" << p << std::endl;
    };
     
    auto res2{ std::async(std::launch::async,fun2) };

    tP1.get_future().wait();
    tP2.get_future().wait();

    signalP.set_value(22);

    return 1;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值