简体   繁体   English

std :: lock_guard似乎给了线程安全,尽管有scoped块

[英]std::lock_guard seems to give thread safety despite scoped block

mutex m;
void thread_function()
{
    static int i = 0;

    for(int j =0; j<1000; j++)
    {
        { //this scope should make this ineffective according to my understanding
        lock_guard<mutex> lock(m);
        }
        i++;

       cout<<i<<endl;
    }
}

I call this function from 2 threads. 我从2个线程调用此函数。 Hence the expected value of int i is 1000*2 = 2000 if the function behaves in thread-safe fashion. 因此,如果函数以线程安全的方式运行,则int i的期望值为1000 * 2 = 2000。

Without the mutex, the result varies from 1990 to 2000 as expected when printing i (due to non atomic int i). 没有互斥体,结果在1990年到2000年之间变化,正如打印i时所预期的那样(由于非原子int i)。 Inserting the lock guard without the scoped block prevents this. 插入没有范围块的锁定防护装置可以防止这种情况发生。

However, by my understanding, having the scoped block around it should make it acquire and release the lock immediatly, hence there is no longer thread safety when writing to int i. 但是,根据我的理解,在它周围使用scoped块应该使它立即获取并释放锁,因此在写入int i时不再有线程安全性。 However, I notice i to be 2000 always. 但是,我注意到我永远是2000。 Am I misunderstanding something? 我误会了什么吗?

Your understanding is correct and that the result is always 2000 is probably machine-dependent. 您的理解是正确的,结果总是2000可能与机器有关。 The reason could be that the synchronization just before the i++ statement on your machine happens to always cause the threads to execute it with sufficient distance in time to avoid the race condition. 原因可能是在机器上的i++语句之前的同步恰好导致线程以足够的时间距离执行它以避免竞争条件。 However, as said, this is not guaranteed. 但是,如上所述,这不能保证。

As others have already told you, the issue is that your i++ is so close to the thread synchronization that it (practically always) manages to do the update before the thread is preempted. 正如其他人已经告诉过你的那样,问题是你的i++非常接近线程同步,以至于它(实际上总是)在线程被抢占之前设法进行更新。

If we change your program like this: 如果我们改变你的程序:

#include <iostream>
#include <thread>
#include <mutex>

std::mutex m;
void thread_function()
{
    static int i = 0;

    for (int j = 0; j < 1000; j++)
    {
        { //this scope should make this ineffective according to my understanding
            std::lock_guard<std::mutex> lock(m);
        }
        std::cout << "Printing some stuff. Weee!" << std::endl; // <- New line
        i++;

        std::cout << i << std::endl;
    }
}

int main()
{
    std::thread t1(thread_function);
    std::thread t2(thread_function);
    t1.join();
    t2.join();
    return 0;
}

Then sometimes the two threads will no longer sum to 2000. You will still hit the race condition less often than if the lock wasn't there, but this just shows a major danger with race conditions and undefined behavior: Your program can actually work most of the time , even if it is strictly wrong according to the standard. 然后有时候两个线程将不再总和到2000.你仍然会比没有锁定时更少地遇到竞争状态,但这只是显示了竞争条件和未定义行为的主要危险:你的程序实际上可以工作最多当时 ,即使按照标准严格错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM