原子操作
概念
- 所谓原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何
context switch - 原子操作可以保证正在工作的动作不被打断,即一旦开始,持续到结束。对比互斥锁优势在于,原子操作是在
C/C++的层面,是无锁操作,既能解决并发问题,又不会导致死锁
原理
X86平台,CPU提供了在指令执行期间对总线加锁的手段。CPU有一根引线#HLOCK pin连接到北桥,如果汇编语言的程序在一条指令前面加上了LOCK前缀,经过汇编以后的机器代码就会使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而把线程锁住- 这样,同一线程上别的
CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性
代码
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
std::vector<std::thread> g_t_; void add_value_test() { int value = 0; auto f = [&](const char* name, int index) { for (int i = 0; i < 10000; i++) { ++value; std::this_thread::sleep_for(std::chrono::milliseconds(5)); std::cout << name << index << " value is : " << value << std::endl; } }; for (int i = 0; i < 100; i++) { g_t_.push_back(std::move(std::thread(f, "thread", i))); } for (int i = 0; i < 100; i++) { g_t_[i].join(); } std::cout << "value is :" << value << std::endl; } |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
std::vector<std::thread> g_t_; void add_value_test() { std::atomic<int> value(0); auto f = [&](const char* name, int index) { for (int i = 0; i < 10000; i++) { ++value; std::this_thread::sleep_for(std::chrono::milliseconds(5)); std::cout << name << index << " value is : " << value.load() << std::endl; } }; for (int i = 0; i < 100; i++) { g_t_.push_back(std::move(std::thread(f, "thread", i))); } for (int i = 0; i < 100; i++) { g_t_[i].join(); } std::cout << "value is :" << value.load() << std::endl; } |
检测内存泄露的工具
VLD
Debug模式,链接vld.lib库,在代码加入头文件
LeakDiag
UMDH
发给子线程的消息主线程能不能捕获
通过 PostThreadMessage
- 发到子线程消息队列中的消息,只能由子线程自己的
GetMessage或PeekMessage取出,主线程不能从自己的消息循环中直接捕获它 - 因为每个线程拥有独立的消息队列
|
1 2 3 4 5 6 7 |
主线程消息队列 ├── 主窗口消息 └── 发给主线程的线程消息 子线程消息队列 ├── 子线程窗口消息 └── 发给子线程的线程消息 |
子线程怎样通知主线程
- 方案
1:向主窗口发送消息
|
1 2 3 4 5 6 7 8 9 |
constexpr UINT WM_WORK_FINISHED = WM_APP + 1; // 子线程 PostMessage( main_window, WM_WORK_FINISHED, result, 0); |
- 直接向主线程发送线程消息
- 线程消息没有对应窗口,因此
msg.hwnd == nullptr - 并且它不会被
DispatchMessage交给窗口过程。必须在消息循环中直接处理: - 所以
GUI程序中通常更推荐方案1
- 线程消息没有对应窗口,因此
|
1 2 3 4 5 6 7 8 9 10 11 |
// 保存主线程 ID DWORD main_thread_id = GetCurrentThreadId(); // 子线程通知主线程: PostThreadMessage( main_thread_id, WM_WORK_FINISHED, result, 0); |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// 主线程消息循环: MSG msg{}; while (GetMessage(&msg, nullptr, 0, 0) > 0) { if (msg.hwnd == nullptr && msg.message == WM_WORK_FINISHED) { int result = static_cast<int>(msg.wParam); continue; } TranslateMessage(&msg); DispatchMessage(&msg); } |
多个子线程,读一个全局布尔变量
shared_ptr循环引用
lambda
windbg
windows调试工具
CoCreateInstance实现
声明:本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ 2022_02_2602/26
- ♥ 2019_11_0511/07
- ♥ 2025_03_2503/25
- ♥ 2022_03_0103/01
- ♥ 2020_11_2002/17
- ♥ 2020_04_2204/23
热评文章
- 2020_05_11_01 0
- 2022_03_07 0
- 2025_03_11 0
- 2020_04_29 0
- 2022_02_26 0
- 2025_03_18 0