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

收录好的博客网站吗买外链有用吗

收录好的博客网站吗,买外链有用吗,wordpress 微信 插件开发,dreamweaver软件是做什么的总结 多线程访问共享数据时需要加锁 多线程数据竞争 假如有一个变量shared_variable被10个线程共享&#xff0c;每个线程在循环中对shared_variable进行 1000 次累加操作&#xff0c;我们期望最终值为10000。 #include <iostream> #include <thread> #include …

总结

多线程访问共享数据时需要加锁

多线程数据竞争

假如有一个变量shared_variable被10个线程共享,每个线程在循环中对shared_variable进行 1000 次累加操作,我们期望最终值为10000。

#include <iostream>
#include <thread>
#include <vector>int shared_variable = 0; // 共享变量void thread_function() {for (int i = 0; i < 1000; ++i) {// 模拟长延迟,增加竞争机会std::this_thread::sleep_for(std::chrono::milliseconds(1));shared_variable++;}
}int main() {const int num_threads = 10;std::vector<std::thread> threads;// 创建多个线程for (int i = 0; i < num_threads; ++i) {threads.emplace_back(thread_function);}// 等待所有线程完成for (auto& t : threads) {t.join();}std::cout << "Final value: " << shared_variable << std::endl; // 输出最终结果return 0;
}

实际运行我们发现,shared_variable值通常会小于 10000,并且每次运行结果不同。这是因为多个线程同时读取和修改shared_variable,导致其值被错误覆盖。++shared_variable是一个非原子操作,包含三步:

  1. 读取当前值。
  2. 加 1。
  3. 写回新值。

在多线程环境中,这三步之间可能会被其他线程打断,导致结果不一致。例如:

  • 线程 A 读取到值 100,准备加 1。
  • 线程 B 同时读取到值 100,也准备加 1。
  • 线程 A 写回值 101。
  • 线程 B 写回值 101(假设线程 B 未看到线程 A 的修改)。

期望的值应为 102,但实际上变为 101,导致错误。这就是在多线程编程中不使用锁导致数据竞争的典型问题。

使用锁同步

  1. List item

锁是一种同步机制,用于协调多个线程对共享资源的访问。它类似于现实生活中的锁,可以确保一次只有一线程能访问特定的资源,其他线程必须等待锁被释放才能继续执行。在多线程编程中,锁的主要作用是防止数据竞争和一致性问题,确保对共享数据的正确操作和访问顺序。

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>std::mutex mtx; // 互斥锁
int shared_variable = 0; // 共享变量void thread_function() {for (int i = 0; i < 1000; ++i) {     std::lock_guard<std::mutex> lock(mtx); // 获取锁shared_variable++;     // 模拟长延迟,增加竞争机会std::this_thread::sleep_for(std::chrono::milliseconds(1));}
}int main() {const int num_threads = 10;std::vector<std::thread> threads;// 创建多个线程for (int i = 0; i < num_threads; ++i) {threads.emplace_back(thread_function);}// 等待所有线程完成for (auto& t : threads) {t.join();}std::cout << "Final value: " << shared_variable << std::endl; // 输出最终结果return 0;
}

复合操作中的竞争条件问题

当shared_vector正在被一个线程修改时,另一个线程可能读取了无效的内存地址,导致内存越界和段错误。例如当多个线程同时执行复合操作时(例如,先检查 size() 再访问元素),仍然需要外部同步,因为复合操作本身不是原子的。

if (vec.size() > 0) { // 操作1:检查条件int value = vec.at(0); // 操作2:访问元素
}

具体的例子如下所示

#include <iostream>
#include <vector>
#include <thread>
#include <chrono>std::vector<int> shared_vector; // 共享的 vector// 写线程,不断向 vector 中添加元素
void writer_thread()
{for (int i = 0; i < 1000000; ++i) {shared_vector.push_back(i); // 1. 线程A添加一个元素,vector不为空std::this_thread::sleep_for(std::chrono::nanoseconds(1)); // 模拟延迟shared_vector.clear(); // 3. 清空 vector}
}// 操作线程,不断清空 vector 并访问最后一个元素
void reader_thread()
{while (true) {if (!shared_vector.empty()) { // 2. 线程B对vector判空std::this_thread::sleep_for(std::chrono::nanoseconds(1)); // 模拟延迟int last_element = shared_vector.at(0); // 4. 尝试访问第一个元素,可能导致越界访问std::cout << "Last element: " << last_element << std::endl;}}
}int main()
{std::thread t1(writer_thread);std::thread t2(reader_thread);t1.join();t2.join();return 0;
}

这种情况还比较好分析,vector在添加元素超过某个size的时候会重新申请一块地址,如果另一个线程还在访问之前的地址,就会造成非法访问的问题

解决方案就是通过锁来保证复合操作的

std::mutex mtx;
std::vector<int> vec;if (mtx.lock()) {if (vec.size() > 0) { int value = vec.at(0);// 处理 value}mtx.unlock();
}

条件变量与线程同步

锁解决了数据竞争的问题,但是没有解决线程顺序执行的问题,例如我们想让3个线程顺序打出ABC,可以使用条件变量

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>// 全局变量
std::mutex mtx;
std::condition_variable cv;
char current_char = 'a'; // 当前应该打印的字符// 打印函数
void print_char(char target_char) {for (int i = 0; i < 5; ++i) { // 每个字符打印5次,可以根据需要调整std::unique_lock<std::mutex> lock(mtx);// 等待轮到自己打印cv.wait(lock, [target_char]() { return current_char == target_char; });// 打印字符std::cout << target_char << std::endl;// 更新当前字符到下一个if (target_char == 'a') {current_char = 'b';} else if (target_char == 'b') {current_char = 'c';} else {current_char = 'a';}// 通知其他线程cv.notify_all();}
}int main() {// 创建三个线程std::thread thread_a(print_char, 'a');std::thread thread_b(print_char, 'b');std::thread thread_c(print_char, 'c');// 等待线程完成thread_a.join();thread_b.join();thread_c.join();return 0;
}

条件变量为什么加锁

条件变量在使用时通常与锁(如 std::mutex)一起使用,主要原因如下:

1. 保证数据一致性和线程安全

条件变量用于线程之间的通信和同步,当线程等待某个条件时,必须确保该条件的状态是被保护起来的。如果没有锁保护,在线程等待条件时,其他线程可能会修改条件相关的数据,导致数据不一致和竞争条件。
例如,在生产者 - 消费者问题中,消费者线程等待队列非空的条件。如果消费者线程在检查队列是否为空的时候不使用锁保护,生产者线程可能会在消费者线程检查的中间过程插入数据,导致检查结果不准确。

void consumer() {while (true) {if (!queue.empty()) { // 没有锁保护,读取共享变量是不安全的int val = queue.front();queue.pop();std::cout << "Consumed: " << val << std::endl;} else {// 等待队列有数据cv.wait(); // 假设有条件变量 cv}}
}

问题:如果多个线程同时检查 queue.empty(),而没有锁保护,可能会导致竞争条件,因为 queue 的状态可能在检查和操作之间发生变化。

2. 确保条件判断的原子性

在使用条件变量时,通常需要进行以下三步操作:

  • 锁定互斥锁。
  • 检查条件是否成立。
  • 如果条件不成立,等待条件变量。

通过互斥锁,可以确保这三步操作是原子的,即在多线程环境下,其他线程不能在步骤 2 和 3 之间修改条件相关的数据。

void consumer() {std::unique_lock<std::mutex> lock(mtx);while (queue.empty()) { // 使用锁保护,并使用 while 避免虚假唤醒cv.wait(lock); // 等待条件变量}int val = queue.front();queue.pop();std::cout << "Consumed: " << val << std::endl;
}

std::unique_lock<std::mutex> lock(mtx); 确保在检查条件和操作队列时,其他线程不能访问队列。while 循环确保即使由于虚假唤醒,线程在真正条件满足之前不会继续执行。

3. 避免虚假唤醒

条件变量的 wait 方法可能出现虚假唤醒(spurious wakeup),即线程在没有明确通知的情况下被唤醒。使用 std::unique_lock 和 while 循环可以避免这种情况。
错误示例(没有使用锁和 while 循环):

void consumer() {if (queue.empty()) {cv.wait(); // 可能出现虚假唤醒}// 虚假唤醒导致进入此处时队列可能仍然为空int val = queue.front();queue.pop();
}

正确示例:

void consumer() {std::unique_lock<std::mutex> lock(mtx);while (queue.empty()) { // 即使有虚假唤醒,也会重新检查条件cv.wait(lock);}int val = queue.front();queue.pop();std::cout << "Consumed: " << val << std::endl;
}
4. 确保线程间的可见性

条件变量和锁的组合使用可以确保线程之间的内存可见性。例如,当线程 A 修改了某个共享变量并通知条件变量,线程 B 通过锁保护可以保证看到线程 A 的修改。

void producer() {{std::lock_guard<std::mutex> lock(mtx);queue.push(1); // 修改共享数据}cv.notify_one(); // 通知消费者
}void consumer() {std::unique_lock<std::mutex> lock(mtx);while (queue.empty()) {cv.wait(lock);}int val = queue.front(); // 看到生产者线程修改后的数据queue.pop();
}

总结
条件变量和锁的组合使用是确保多线程环境下数据一致性和线程安全的关键。锁保护共享数据的访问,避免竞争条件;条件变量通过条件等待和通知机制,实现线程间的通信和同步。只有在锁的保护下,条件变量才能正确地工作,并保证线程之间的数据可见性。

http://www.mmbaike.com/news/65262.html

相关文章:

  • 哪家做网站做的好西安seo管理
  • 网站评论管理怎么做的百度推广的费用
  • 精英学校老师给学生做的网站广州seo工资
  • 重庆网站建设培训机构学费ds2600ii色带
  • 网站开发技术招聘资源最多的磁力搜索引擎
  • 怎样做一元购网站成都正规搜索引擎优化
  • wordpress 08影院模板泰安seo
  • 厦门网站建设公司排名seo对网店推广的作用有哪些
  • 网站建设问题清单外贸建站推广哪家好
  • 街道政府网站三基建设汇报西安高端模板建站
  • 网站编辑年终总结上海公关公司
  • 南海建设工程交易中心网站域名权重查询工具
  • wordpress显示作者列表seo是什么服
  • 接单网站源码安徽疫情最新情况
  • 泰安新闻完整版应用商店优化
  • o2o网站运维建设方案交换友链平台
  • 设计师网址导航sdc学seo如何入门
  • 温州网站建设科技有限公司拼多多seo是什么意思
  • 开源网站建设百度广告语
  • 申请网站做自己的产品企业策划书
  • 网站建设管理汇报业务推广方案怎么写
  • 赤壁网站设计如何让百度快速收录网站文章
  • 帮别人做海报网站seo是什么的简称
  • 东丽区做网站如何制作简易网站
  • 成都建设网站的公司有哪些英文seo是什么
  • 网站栏目是什么网站建设推广专家服务
  • linchong WordPress网站seo源码
  • wordpress车间seo网站编辑是做什么的
  • 网站系统建设预算模拟搜索点击软件
  • 网站外链工具郑州热门网络推广免费咨询