提升,互斥量概念

发布于 2025-01-06 08:40:47 字数 458 浏览 0 评论 0原文

我是多线程编程的新手,对互斥体的工作原理感到困惑。在 Boost::Thread 手册中,它指出:

互斥体保证只有一个线程可以锁定给定的互斥体。如果代码段被互斥锁定和解锁包围,则可以保证一次只有一个线程执行该代码段。当该线程解锁互斥体时,其他线程可以进入该代码区域:

我的理解是,互斥体用于保护一段代码不被多个线程同时执行,不是 保护变量的内存地址。我很难理解这个概念,如果我有两个不同的函数尝试写入同一内​​存地址会发生什么。

Boost库中是否有这样的东西:

  1. 锁定变量的内存地址,例如double x,lock(x);所以 具有不同功能的其他线程无法写入 x。
  2. 对 x 做一些事情,例如 x = x + rand();
  3. 解锁(x)

谢谢。

I am new to multi-threading programming, and confused about how Mutex works. In the Boost::Thread manual, it states:

Mutexes guarantee that only one thread can lock a given mutex. If a code section is surrounded by a mutex locking and unlocking, it's guaranteed that only a thread at a time executes that section of code. When that thread unlocks the mutex, other threads can enter to that code region:

My understanding is that Mutex is used to protect a section of code from being executed by multiple threads at the same time, NOT protect the memory address of a variable. It's hard for me to grasp the concept, what happen if I have 2 different functions trying to write to the same memory address.

Is there something like this in Boost library:

  1. lock a memory address of a variable, e.g., double x, lock (x); So
    that other threads with a different function can not write to x.
  2. do something with x, e.g., x = x + rand();
  3. unlock (x)

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

許願樹丅啲祈禱 2025-01-13 08:40:47

互斥体本身仅确保在任何给定时间只有一个执行线程可以锁定互斥体。您需要确保仅在互斥体锁定时才发生关联变量的修改。

C++ 确实为您提供了一种比 C 等语言更容易做到这一点的方法。在 C 中,正确编写代码几乎取决于您,确保在修改变量的任何地方,首先锁定互斥体(并且,当然,完成后解锁)。

在 C++ 中,将其全部封装到具有一些运算符重载的类中非常容易:

class protected_int {
    int value; // this is the value we're going to share between threads
    mutex m;
public:
    operator int() { return value; } // we'll assume no lock needed to read
    protected_int &operator=(int new_value) {
        lock(m);
        value = new_value;
        unlock(m);
        return *this;
    }
};

显然我对此进行了很多简化(以至于它可能毫无用处),但希望您能明白这一点,这是最重要的代码只是将 protected_int 对象视为普通变量。

然而,当您这样做时,每次您向互斥体赋值时都会自动锁定它,并在之后立即解锁。当然,这几乎是最简单的情况 - 在许多情况下,您需要执行一些操作,例如锁定互斥体,一致修改两个(或更多)变量,然后解锁。然而,无论复杂性如何,我们的想法仍然是将进行修改的所有代码集中在一个位置,因此您不必担心在代码的其余部分中锁定互斥体。当你确实有两个或多个像这样的变量在一起时,你通常必须锁定互斥锁以进行读取,而不仅仅是写入 - 否则你很容易得到一个不正确的值,其中一个变量已被修改,而另一个变量尚未修改。 t。

The mutex itself only ensures that only one thread of execution can lock the mutex at any given time. It's up to you to ensure that modification of the associated variable happens only while the mutex is locked.

C++ does give you a way to do that a little more easily than in something like C. In C, it's pretty much up to you to write the code correctly, ensuring that anywhere you modify the variable, you first lock the mutex (and, of course, unlock it when you're done).

In C++, it's pretty easy to encapsulate it all into a class with some operator overloading:

class protected_int {
    int value; // this is the value we're going to share between threads
    mutex m;
public:
    operator int() { return value; } // we'll assume no lock needed to read
    protected_int &operator=(int new_value) {
        lock(m);
        value = new_value;
        unlock(m);
        return *this;
    }
};

Obviously I'm simplifying that a lot (to the point that it's probably useless as it stands), but hopefully you get the idea, which is that most of the code just treats the protected_int object as if it were a normal variable.

When you do that, however, the mutex is automatically locked every time you assign a value to it, and unlocked immediately thereafter. Of course, that's pretty much the simplest possible case -- in many cases, you need to do something like lock the mutex, modify two (or more) variables in unison, then unlock. Regardless of the complexity, however, the idea remains that you centralize all the code that does the modification in one place, so you don't have to worry about locking the mutex in the rest of the code. Where you do have two or more variables together like that, you generally will have to lock the mutex to read, not just to write -- otherwise you can easily get an incorrect value where one of the variables has been modified but the other hasn't.

情话难免假 2025-01-13 08:40:47

不,boost(或其他地方)中没有任何东西会像这样锁定内存。
您必须保护访问您想要保护的内存的代码。

如果我有两个不同的函数尝试写入同一个函数会发生什么
内存地址。

假设您的意思是在不同线程中执行 2 个函数,则两个函数都应锁定相同的互斥锁,因此在给定时间只有一个线程可以写入该变量。

访问(读取或写入)同一变量的任何其他代码也必须锁定同一互斥锁,否则将导致不确定的行为。

No, there is nothing in boost(or elsewhere) that will lock memory like that.
You have to protect the code that access the memory you want protected.

what happen if I have 2 different functions trying to write to the same
memory address.

Assuming you mean 2 functions executing in different threads, both functions should lock the same mutex, so only one of the threads can write to the variable at a given time.

Any other code that accesses (either reads or writes) the same variable will also have to lock the same mutex, failure to do so will result in indeterministic behavior.

你丑哭了我 2025-01-13 08:40:47

可以使用 对某些类型执行非阻塞原子操作Boost.Atomic。这些操作是非阻塞的,并且通常比互斥体快得多。例如,要以原子方式添加某些内容,您可以执行以下操作:

boost::atomic<int> n = 10;
n.fetch_add(5, boost:memory_order_acq_rel);

此代码以原子方式将 5 添加到 n

It is possible to do non-blocking atomic operations on certain types using Boost.Atomic. These operations are non-blocking and generally much faster than a mutex. For example, to add something atomically you can do:

boost::atomic<int> n = 10;
n.fetch_add(5, boost:memory_order_acq_rel);

This code atomically adds 5 to n.

握住我的手 2025-01-13 08:40:47

为了保护两个不同函数中的多个线程共享的内存地址,两个函数必须使用相同互斥体...否则您将遇到这样的情况:任一函数中的线程都可以不加区别地访问相同的“受保护”内存区域。

因此,boost::mutex非常适合您描述的场景,但您只需确保对于您正在保护的给定资源,到该资源的所有路径都锁定该资源的完全相同的实例。 boost::mutex 对象。

In order to protect a memory address shared by multiple threads in two different functions, both functions have to use the same mutex ... otherwise you will run into a scenario where threads in either function can indiscriminately access the same "protected" memory region.

So boost::mutex works just fine for the scenario you describe, but you just have to make sure that for a given resource you're protecting, all paths to that resource lock the exact same instance of the boost::mutex object.

不奢求什么 2025-01-13 08:40:47

我认为您缺少的细节是“代码部分”是代码的任意部分。它可以是两个函数、半个函数、一行或其他任何东西。

因此,当两个不同函数访问共享数据时持有相同互斥锁的部分,“被互斥锁锁定和解锁包围的代码部分”,因此“保证只有一个线程在一次执行该部分代码”。

另外,这也解释了互斥体的一项属性。它并不声称这是他们拥有的唯一财产。

I think the detail you're missing is that a "code section" is an arbitrary section of code. It can be two functions, half a function, a single line, or whatever.

So the portions of your 2 different functions that hold the same mutex when they access the shared data, are "a code section surrounded by a mutex locking and unlocking" so therefore "it's guaranteed that only a thread at a time executes that section of code".

Also, this is explaining one property of mutexes. It is not claiming this is the only property they have.

放血 2025-01-13 08:40:47

您对互斥体的理解是正确的。它们保护锁定和解锁之间的代码部分。

根据两个线程写入内存同一位置时发生的情况,它们被序列化。一个线程写入其值,另一个线程写入它。这样做的问题是,您不知道哪个线程将首先(或最后)写入,因此代码不是确定性的。

最后,为了保护变量本身,你可以在原子变量中找到一个近概念。原子变量是受编译器或硬件保护的变量,并且可以原子方式修改。也就是说,您注释的三个阶段(读取、修改、写入)是原子发生的。看看 Boost atomic_count

Your understanding is correct with respect to mutexes. They protect the section of code between the locking and unlocking.

As per what happens when two threads write to the same location of memory, they are serialized. One thread writes its value, the other thread writes to it. The problem with this is that you don't know which thread will write first (or last), so the code is not deterministic.

Finally, to protect a variable itself, you can find a near concept in atomic variables. Atomic variables are variables that are protected by either the compiler or the hardware, and can be modified atomically. That is, the three phases you comment (read, modify, write) happen atomically. Take a look at Boost atomic_count.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文