【问题标题】:What does it mean to lock a resource using pthread_mutex_lock?使用 pthread_mutex_lock 锁定资源是什么意思?
【发布时间】:2023-03-18 02:08:01
【问题描述】:

我是多线程的新手,我很难理解互斥。

这是 pthread_mutex_lock 的原型

int pthread_mutex_lock(pthread_mutex_t *mutex);

手册页说The mutex object referenced by mutex shall be locked by calling pthread_mutex_lock().

首先我的理解是,您使用互斥锁来锁定共享资源,以便任何时候只有一个线程可以访问它。为了便于讨论,假设共享资源是一个名为myVariable 的全局变量。现在如果我们想锁定 myVariable,我应该可以使用锁定机制锁定myVariable,但锁定mutex object 是什么意思?我的意思是如果我打电话给pthread_mutex_lock(&someMutex),我是锁定myVariable 还是别的什么?

总而言之,如果我想使用互斥,我不应该做类似pthread_mutex_lock(myVariable) 的事情而不是做pthread_mutex_lock(&someMutex) 吗?

另外,这个someMutex 对象如何对应于myVariable?这个someMutex对象如何锁定对myVariable的访问?

附:假设我已经在自己之前声明了someMutex

附言我有一种感觉,这个问题可能很宽泛,但话又说回来,这不应该是因为我问的是实际上有特定答案的东西(如果我错了,请纠正我)。

【问题讨论】:

  • Mutex 最初被描述为像孩子们的游戏,“Button Button, who got the Button”。如果您有按钮,则仅允许您“触摸”“共享资源”...... Mutex 是按钮,当您的 pthread_mutex_lock() 成功时,您将获得它(逻辑上)。然后,您可以“读取”或“修改”共享资源。完成后,您“解锁”互斥锁,使其可用于其他线程。注意:这是一个简单的/初学者/不完整的描述,但它应该让你开始。
  • 哦,那么在这种情况下,我可以说使用相同的互斥锁来锁定不同的变量吗?假设我可以调用 pthread_mutex_lock(&someMutex) 来锁定 myVariable 和 yourVariable 吗?由于互斥锁不是特定于特定变量(或您所说的资源),我应该能够使用单个互斥锁来处理程序中的所有内容,对吧?
  • 例如,您可以有一个互斥锁控制对所有全局变量的所有访问...您必须考虑所有线程可能需要访问受互斥锁保护的共享资源的频率...它是您需要多少互斥锁以及它们将锁定什么的设计决策。
  • 互斥锁不锁定共享资源,它们锁定部分代码。程序员有责任确保任何共享资源只被相应互斥锁锁定的代码段触及。

标签: c multithreading pthreads mutex


【解决方案1】:

互斥体不知道互斥体和它所保护的对象之间的关联,也不一定知道。假设我们有两个人正在合作,他们需要共享一辆车。我们不希望一个人在另一个人使用汽车时尝试使用它。他们可以制定一个简单的规则——除非你拿着红萝卜,否则不要乱弄汽车。由于只有一个人可以握住萝卜,确保他们在尝试使用汽车时不会相互冲突。萝卜不必知道它在“保护”汽车。只要他们俩都让汽车独自一人,除非他们是拿着萝卜的人,萝卜就会保护汽车。

互斥体是萝卜。锁定互斥锁可以握住萝卜,等到其他人在需要时将其放下。解锁互斥锁会将萝卜放在其他人可以拿到的地方。

互斥锁保护的变量或对象是汽车。萝卜保护汽车不是来自萝卜所做的任何事情,而是来自每个遵守规则的人,除非你有萝卜,否则不要碰汽车。互斥体保护对象也是如此。

【讨论】:

  • 不需要萝卜来保护汽车。有一个更简单的规则:除非你坐在驾驶座上,否则不要开车。但我可以从现实生活中举一个类似的例子:当许多开发人员想对某个共享文件进行更改时,我就听说过软件项目。他们会有一顶特殊的帽子,挂在项目经理的办公室里,规则是,除非你戴着帽子,否则不要编辑文件。
【解决方案2】:

someMutex基本上只是一个数值变量,不直接对应myVariable

一般顺序概念

lock(someMutex) {
    while (someMutex != 0) {}
    someMutex = 1;
}

unlock(someMutex) {
    someMutex = 0;
}

【讨论】:

    【解决方案3】:

    互斥锁保护一个代码区域,因此一次只有一个执行线程会执行该区域。

    互斥锁是一个基本的构建块,您有责任应用它来获得所需的结果。

    如果你想改变一个共享变量,你可以这样做:

    void changeit(int val)
    {
        pthread_mutex_lock(&someMutex);
        global_variable = val;
        pthread_mutex_unlock(&someMutex);
    }
    

    这部分意味着一次只有 1 个线程会在互斥锁的锁定/解锁之间执行代码。这是为了确保

    • global_variable = val;正在以原子方式运行,例如2 个作业同时运行,不能保证结果会是任何有意义的值 (不保证单个赋值语句是原子执行的或作为汇编/机器代码中的一条指令)

    • 读取 global_variable 的任何人都将在有人更改它之前或之后完全这样做,因此他们看不到任何正在更改的不一致值。

    这也意味着任何其他访问(读取和/或写入) global_variable 的人也必须在同一个互斥锁被锁定时这样做,例如要读取变量,您可以这样做:

    int readit(void)
    {
        int val;
        pthread_mutex_lock(&someMutex);
        val = global_variable;
        pthread_mutex_unlock(&someMutex);
        return val;
    }
    

    所以,someMutex 对应于 global_variable 仅在您的代码编写方式上,它依赖于程序员您才能正确执行 - global_variablesomeMutex 之间没有内在联系。

    如果连接两个变量对您的程序有意义,并且必须始终一起读取或写入,则互斥锁允许您这样做 - 而不是像上面的代码所示读取/写入单个变量,您可以读取/在持有互斥锁时更改 2 个变量。同样,互斥锁对这两个变量一无所知,其影响在于代码的结构。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-19
      • 1970-01-01
      • 2011-02-21
      • 1970-01-01
      相关资源
      最近更新 更多