视频上传下载网站建设泰和县建设局网站
2026/1/28 19:30:04 网站建设 项目流程
视频上传下载网站建设,泰和县建设局网站,wordpress app 服务端,seo推广博主介绍#xff1a;程序喵大人 35 - 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章#xff0c;首发gzh#xff0c;见文末#x1f447;#x…博主介绍程序喵大人35 - 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章首发gzh见文末记得订阅专栏以防走丢C基础系列专栏C语言基础系列专栏C大佬养成攻略专栏C训练营个人网站C11 多线程相关的知识点本文目录如何创建线程如何加锁如何使用原子操作如何使用条件变量如何优雅的执行异步任务如何创建线程C11之前你可能使用pthread_xxx来创建线程繁琐且不易读C11引入了std::thread来创建线程支持对线程join或者detach。直接看代码#includeiostream#includethreadusingnamespacestd;intmain(){autofunc[](){for(inti0;i10;i){couti ;}coutendl;};std::threadt(func);if(t.joinable()){t.detach();}autofunc1[](intk){for(inti0;ik;i){couti ;}coutendl;};std::threadtt(func1,20);if(tt.joinable()){// 检查线程可否被jointt.join();}return0;}上述代码中函数func和func1运行在线程对象t和tt中从刚创建对象开始就会新建一个线程用于执行函数调用join函数将会阻塞主线程直到线程函数执行结束线程函数的返回值将会被忽略。如果不希望线程被阻塞执行可以调用线程对象的detach函数表示将线程和线程对象分离新的线程与主线程没有任何关联线程资源在任务结束后会由操作系统自动回收。如果没有调用join或者detach函数假如线程函数执行时间较长此时线程对象的生命周期结束调用析构函数清理资源这时可能会发生crash这里有两种解决办法一个是调用join()保证线程函数的生命周期和线程对象的生命周期相同另一个是调用detach()将线程和线程对象分离这里需要注意如果线程已经和对象分离那我们就再也无法控制线程什么时候结束了不能再通过join来等待线程执行完。C11还提供了获取线程id或者系统cpu个数获取thread native_handle让线程休眠等功能std::threadt(func);cout当前线程ID t.get_id()endl;cout当前cpu个数 std::thread::hardware_concurrency()endl;autohandlet.native_handle();// handle可用于pthread相关操作std::this_thread::sleep_for(std::chrono::seconds(1));如何加锁在C11中加锁可以使用std::mutexmutex主要有四种std::mutex独占的互斥量不能递归使用不带超时功能std::recursive_mutex递归互斥量可重入不带超时功能std::timed_mutex带超时的互斥量不能递归std::recursive_timed_mutex带超时的互斥量可以递归使用最常用的就是std::mutex其它三种我也没用过std::mutex mutex_;intmain(){autofunc1[](intk){mutex_.lock();for(inti0;ik;i){couti ;}coutendl;mutex_.unlock();};std::thread threads[5];for(inti0;i5;i){threads[i]std::thread(func1,200);}for(autoth:threads){th.join();}return0;}mutex还可以搭配RAII方式的锁封装类一起使用可以动态的释放锁资源防止线程由于编码失误导致始终持有锁。C11主要有std::lock_guard和std::unique_lock两种RAII方式使用方式类似autofunc1[](intk){// std::lock_guardstd::mutex lock(mutex_);std::unique_lockstd::mutexlock(mutex_);for(inti0;ik;i){couti ;}coutendl;};std::lock_guard相比于std::unique_lock更加轻量级少了一些成员函数std::unique_lock类有unlock函数可以手动释放锁所以条件变量都配合std::unique_lock使用而不是std::lock_guard因为条件变量在wait时需要有手动释放锁的能力具体关于条件变量后面会讲到。如何使用原子操作C11提供了原子类型std::atomic理论上这个T可以是任意类型但是我平时只存放整型别的还真的没用过整型有这种原子变量已经足够方便就不需要使用std::mutex来保护该变量啦。看一个带锁计数器的代码structOriginCounter{// 普通的计数器intcount;std::mutex mutex_;voidadd(){std::lock_guardstd::mutexlock(mutex_);count;}voidsub(){std::lock_guardstd::mutexlock(mutex_);--count;}intget(){std::lock_guardstd::mutexlock(mutex_);returncount;}};而用原子变量就方便的多structNewCounter{// 使用原子变量的计数器std::atomicintcount;voidadd(){count;}voidsub(){--count;}intget(){returncount.load();}};如何使用条件变量条件变量是C11引入的一种同步机制它可以阻塞一个线程或者个线程直到有线程通知或者超时才会唤醒正在阻塞的线程条件变量需要和锁配合使用这里的锁就是上面介绍的std::unique_lock。这里使用条件变量实现一个CountDownLatchclassCountDownLatch{public:explicitCountDownLatch(uint32_tcount):count_(count);voidCountDown(){std::unique_lockstd::mutexlock(mutex_);--count_;if(count_0){cv_.notify_all();}}voidAwait(uint32_ttime_ms0){std::unique_lockstd::mutexlock(mutex_);while(count_0){if(time_ms0){cv_.wait_for(lock,std::chrono::milliseconds(time_ms));}else{cv_.wait(lock);}}}uint32_tGetCount()const{std::unique_lockstd::mutexlock(mutex_);returncount_;}private:std::condition_variable cv_;mutablestd::mutex mutex_;uint32_tcount_0;};关于条件变量其实还涉及到通知丢失和虚假唤醒问题可以看这篇文章通知丢失和虚假唤醒。如何优雅的执行异步任务你可能已经猜到了我要介绍的就是async关于异步操作可以优先使用async看这段代码#includefunctional#includefuture#includeiostream#includethreadusingnamespacestd;intfunc(intin){returnin1;}intmain(){autoresstd::async(func,5);// res.wait();coutres.get()endl;// 阻塞直到函数返回return0;}使用async异步执行函数是不是方便多啦。async具体语法如下async(std::launch::async|std::launch::deferred,func,args...);第一个参数是创建策略std::launch::async表示任务执行在另一线程std::launch::deferred表示延迟执行任务调用get或者wait时才会执行不会创建线程惰性执行在当前线程。如果不明确指定创建策略以上两个都不是async的默认策略而是未定义它是一个基于任务的程序设计内部有一个码字不易欢迎大家点赞关注评论谢谢

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询