当前位置: 首页 > news >正文

乌兰察布建设局网站柳州专业网站建设加盟

乌兰察布建设局网站,柳州专业网站建设加盟,深圳培训公司网站建设,网站域名过户查询文章目录thread 创建mutexmutexrecursive_mutextimed_mutexlock_guard原子操作atomic条件变量condition_variable其他线程安全问题shared_ptr单例模式C 线程库是 C11 标准中引入的一个特性#xff0c;它使得 C 在语言级别上支持多线程编程#xff0c;不需要依赖第三方库或操作… 文章目录thread 创建mutexmutexrecursive_mutextimed_mutexlock_guard原子操作atomic条件变量condition_variable其他线程安全问题shared_ptr单例模式C 线程库是 C11 标准中引入的一个特性它使得 C 在语言级别上支持多线程编程不需要依赖第三方库或操作系统 API。C 线程库主要包括以下几个部分std::thread创建和管理子线程的类std::mutex互斥锁用于保护共享数据的访问std::condition_variable条件变量用于同步线程之间的状态std::future 和 std::promise异步任务和结果的封装std::async启动异步任务的函数 thread 创建 thread std::thread 类的构造函数 std::thread 是一个类它表示一个可执行的线程。你可以用它来创建和管理子线程让它们并发地执行不同的任务。std::thread 有以下几个特点 它不可拷贝只能移动。如上(3)(4)它可以被 join 或 detachjoin 表示等待线程结束detach 表示让线程自行运行它有一个唯一的标识符 std::thread::id可以用来区分不同的线程 在命名空间 this_thread下有一个 get_id 函数可以帮助我们获取线程 id yield可以使当前线程让出时间片 sleep_untilsleep 到特定时间点 sleep_forsleep 一段时间 一个双线程循环打印的例子 #include iostream #include threadusing namespace std;void print(int n) {for (int i 0; i n; i) {cout this_thread::get_id() : i endl; // 打印 [线程id]:ithis_thread::sleep_for(chrono::seconds(1)); // sleep 1 秒} }int main() {thread t1(print, 100);thread t2(print, 100);t1.join();t2.join();return 0; }mutex mutex 例一给上面的代码加锁 #include iostream #include thread #include mutexusing namespace std;mutex mtx; // 创建一把锁void print(int n) {mtx.lock(); // 加锁for (int i 0; i n; i) {cout this_thread::get_id() : i endl; // 打印 [线程id]:ithis_thread::sleep_for(chrono::milliseconds(100)); // sleep 100 ms}mtx.unlock(); // 解锁 }int main() {thread t1(print, 100);thread t2(print, 100);t1.join();t2.join();return 0; }例二 如果锁是创建在局部则要通过函数参数传入 由于锁不支持拷贝所以必须通过引用传入又由于可变模板参数会默认识别成传值所以必须先使用 ref 来强制转换成引用。 #include iostream #include thread #include mutexusing namespace std;void print(int n, mutex mtx) {mtx.lock(); // 加锁for (int i 0; i n; i) {cout this_thread::get_id() : i endl; // 打印 [线程id]:ithis_thread::sleep_for(chrono::milliseconds(100)); // sleep 100 ms}mtx.unlock(); // 解锁 }int main() {mutex mtx; // 创建一把锁thread t1(print, 100, ref(mtx)); // 必须使用 ref 来传引用thread t2(print, 100, ref(mtx));t1.join();t2.join();return 0; }例三 配合 vector 和 lambda 使用 #include iostream #include thread #include mutex #include vectorusing namespace std;int main() {mutex mtx; // 创建一把锁int x 0, n 10, m;cin m;vectorthread v(m);for (int i 0; i m; i) {v[i] thread([]() {mtx.lock(); // 加锁for (int i 0; i n; i) {cout this_thread::get_id() : i endl; // 打印 [线程id]:ithis_thread::sleep_for(chrono::milliseconds(100)); // sleep 100 ms}mtx.unlock(); // 解锁});}for (auto t : v) {t.join();}return 0; }recursive_mutex 如果在递归函数中使用普通的互斥锁会造成死锁因为当一个线程执行到 unlock 之前就可能会递归调用自己然后从头开始执行当再次遇到 lock 时由于之前没有执行 unlock就会死锁。 而 recursive_mutex 可以防止递归造成的死锁它在每次 lock 的时候会判断是不是当前线程如果是就不用阻塞可以继续向下执行了。 timed_mutex 定时互斥锁该类锁可以设置锁住的时间。 由它的两个成员实现 try_lock_for 和 try_lock_until. 到时间后我们不需要手动解锁而是自动解锁。 lock_guard 智能锁通过 RAII 技术实现。 它的实现类似于如下方法 templateclass Lock class LockGuard { public:LockGuard(Lock lk) : _lock(lk) {_lock.lock();}~LockGuard() {_lock.unlock();} private:Lock _lock; };例 int main() {mutex mtx; // 创建一把锁atomicint x 0;//int x 0;int n 100, m;cin m;vectorthread v(m);for (int i 0; i m; i) {v[i] thread([]() {for (int i 0; i n; i) {lock_guardmutex lk(mtx); // 智能锁cout this_thread::get_id() : i endl;this_thread::sleep_for(chrono::microseconds(100));}});}for (auto t : v) {t.join();}cout x endl;return 0; }注unique_guard 比 lock_guard 多一个支持手动加锁的解锁的功能。 原子操作 atomic 我们知道 操作不是线程安全的要避免多线程同时修改造成的数据不一致的问题可以通过加锁来解决。 但是互斥锁会产生上下文切换的开销容易产生死锁。更好的解决方法是使用原子操作。 CAS Compare Set或 Compare Swap是一种原子操作也就是说它是一个不会被其他线程打断的操作。CAS 有三个操作数内存值 V旧的预期值 A要修改的新值 B。CAS 的过程是这样的先比较内存值 V 和旧的预期值 A 是否相等如果相等就用新值 B 替换内存值 V如果不相等就放弃操作或者重试。CAS 可以用于实现无锁算法避免多线程同时修改同一数据时产生的数据不一致问题。 C11 中的 atomic 类就是 CAS 的一种实现。 例 #include iostream #include thread #include vectorusing namespace std;int main() {//int x 0;atomicint x 0;int n 100000, m;cin m;vectorthread v(m);for (int i 0; i m; i) {v[i] thread([]() {for (int i 0; i n; i) {x; // 原子操作}});}for (auto t : v) {t.join();}cout x endl;return 0; }条件变量 condition_variable 条件变量是一种同步原语用于让线程在某个条件发生时才继续执行。 条件变量与互斥锁配合使用让线程在等待条件时释放锁从而避免竞争状态。条件变量提供了一种原子操作即解锁并睡眠的操作以及唤醒并加锁的操作。条件变量有两个动作等待wait和通知notify。等待动作会让线程挂起并释放已经持有的锁。通知动作会唤醒一个或多个等待的线程并让它们重新获取锁。 在 C11 中你可以使用 std::condition_variable 类来创建和操作条件变量。你需要配合一个互斥锁std::mutex和一个谓词std::functionbool()来使用条件变量。你可以调用条件变量的成员函数如wait()notify_one()notify_all()等来实现线程间的同步。 predicate(2) 是增加了谓词的版本pred 是一个 std::functionbool()它返回 false 则表示阻塞返回 true 时解除阻塞。 例创建两个线程交替打印 0~100如线程 t2 先打印 0则下面必须是另一个线程 t1 打印 1然后 t2 打印 2 … 这是一个运用条件变量解决的经典场景我们可以让一个线程打印完一个数之后立马通知另一个线程从而保证两个线程交替进行。 #include iostream #include thread #include mutex #include condition_variableusing namespace std;int main() {int i 0;int n 100;mutex mtx;condition_variable cv;bool ready true; // 开始标志初始为 true可以使线程 t2 先打印thread t1([]() {while (i n) {unique_lockmutex lock(mtx); // 条件变量需要的互斥锁cv.wait(lock, [ready]() {return !ready; }); // 如果 ready 为 true 则阻塞cout this_thread::get_id() : i endl;i;ready true; // 更改条件cv.notify_one();// 唤醒另一个线程}});thread t2([]() {while (i n) {unique_lockmutex lock(mtx);cv.wait(lock, [ready]() {return ready; }); // 如果 ready 为 false 则阻塞cout this_thread::get_id() : i endl;i;ready false; // 更改条件cv.notify_one();// 唤醒另一个线程}});t1.join();t2.join();return 0; }例2生产者消费者模型 #include iostream #include thread #include mutex #include condition_variable #include queuestd::mutex mtx; // 互斥锁 std::condition_variable cv; // 条件变量 std::queueint q; // 共享队列 bool finished false; // 结束标志void producer(int n) {for (int i 0; i n; i) {std::unique_lockstd::mutex lock(mtx); // 加锁std::this_thread::sleep_for(std::chrono::milliseconds(100));q.push(i); // 生产数据std::cout produced i \n;lock.unlock(); // 解锁cv.notify_one(); // 通知消费者}{std::unique_lockstd::mutex lock(mtx); // 加锁finished true; // 设置结束标志}cv.notify_all(); // 通知所有消费者 }void consumer() {while (true) {std::unique_lockstd::mutex lock(mtx); // 加锁cv.wait(lock, [] {return finished || !q.empty(); }); // 等待条件成立结束或队列非空if (finished q.empty()) {break; // 结束且队列空退出循环}std::this_thread::sleep_for(std::chrono::milliseconds(100));int x q.front(); // 取出数据q.pop();std::cout std::this_thread::get_id() : consumed x \n;} }int main() {std::thread t1(producer, 10); // 创建生产者线程生产10个数据std::thread t2(consumer); // 创建消费者线程1std::thread t3(consumer); // 创建消费者线程2t1.join();t2.join();t3.join();return 0; }运行结果 其他线程安全问题 shared_ptr Qshared_ptr 是线程安全的吗 Ashared_ptr 的引用计数保证是线程安全的但访问资源不是如果你想在多个线程之间共享同一个 shared_ptr 指向的对象你需要使用互斥锁或原子操作来保护它。 单例模式 饿汉模式 特点 不允许随便创建对象构造函数私有防拷贝main 函数之前就创建初始化对象 缺点 对象初始化麻烦影响程序启动速度多个单例类如果有依赖顺序关系无法控制 懒汉模式 特点 不允许随便创建对象构造函数私有防拷贝第一次使用对象时创建对象 缺点 多个线程使用第一次调用存在竞争的线程安全问题。 所以饿汉模式不用考虑线程安全问题而懒汉模式有线程安全问题 下面是一个懒汉模式的代码示例 class Singleton { public:static Singleton* GetInstance() {if (_spInst nullptr) {_spInst new Singleton;}return _spInst;} private:Singleton() {}Singleton(const Singleton) delete;static Singleton* _spInst; };Singleton* Singleton::_spInst nullptr;如果有多个线程同时调用 GetInstance可能会创建多个对象实例违反了单例模式的原则。 这个问题可以通过加锁解决 下面的代码是一个双重检查加锁的懒汉模式的实现双重检查加锁是一种用于减少获取锁的开销的软件设计模式。程序先检查锁定条件只有当检查表明需要锁定时才获取锁然后检查是否已经实例化对象防止创建多个对象。 class Singleton { public:static Singleton* GetInstance() {if (_spInst nullptr) { // 第一重检查std::unique_lockstd::mutex lock(_mtx);if (_spInst nullptr) { // 第二重检查_spInst new Singleton;}}return _spInst;} private:Singleton() {}Singleton(const Singleton) delete;static Singleton* _spInst;static std::mutex _mtx; };Singleton* Singleton::_spInst nullptr; std::mutex Singleton::_mtx;你会发现这两重检查缺一不可如果缺少了第一重检查那么每次调用 GetInstance 都会加锁解锁增加了获取锁的开销。如果缺少了第二重检查那么两个线程会竞争一把锁当其中一个线程加锁之后另一个线程会阻塞当一个线程完成了对象的实例化并释放锁另一个线程就会获取锁此时如果没有第二重检查那么它就会再创建一个对象违反了单例模式的原则。 第二种线程安全的懒汉模式的实现方式 它利用了静态局部对象只会在第一次调用时初始化特性。 class Singleton { public:static Singleton* GetInstance() {static Singleton _s;return _s;} private:Singleton() {}Singleton(const Singleton) delete;Singleton operator(Singleton const) delete; };但是这种实现方式有一个缺点它在 C11 之前不能保证是线程安全的因为 C11 之前局部静态对象的构造函数并不能保证是线程安全的。
http://www.w-s-a.com/news/2980043/

相关文章:

  • 单位网站建设情况字体模板素材免费下载网站
  • 班级网站设计模板新手建什么网站赚钱
  • wordpress 做网站开发公司工程管理岗好还是设计岗好
  • 模型评测网站怎么做抖音带运营的执行老大
  • 一个空间放多个网站用element做的网站
  • 个性化网站建设费用百度识图在线使用
  • thinkphp做的网站怎么打开网络推广对产品销售的重要性
  • 学设计的网站网站某个链接失效
  • 网站建设策划书附录国外服务器多少钱一个月
  • 纺织厂网站模板招商网站建设网
  • 可不可以建网站做微商自己网站上做支付宝怎么收费的
  • 简单做网站需要学什么软件开发公司组织结构图
  • 郓城网站建设宁波百度推广优化
  • 企业网站建设的定位网站后台换qq
  • 北京做网站定制价格图表设计 网站
  • 企业营销型网站费用公司网页制作免费
  • 网站源码破解版广东网络营销全网推广策划
  • 网站建设预览简单的asp网站
  • 铜仁市住房和城乡建设厅网站自己做网站要办手续吗
  • 大连做公司网站微网站 获取手机号
  • seo网站诊断网站过场动画
  • 如何用eclipse做网站建设银行辽宁招聘网站
  • 网站域名需要申请上海公司网站建设
  • 飓风算法恢复的网站青岛本地网站
  • 网站建设初期工作方案idea可以做网站吗
  • 网站打开慢是什么原因网站建设信息安全要求
  • 宁波seo网站排名优化网站建设素材网页
  • 做照片有那些网站好昆明如何做百度的网站
  • 网站运营如何做温州建设集团有限公司网站
  • 做网站分辨率多少重庆定制网站开发