为什么std :: mutex会花费很长时间,高度不规则的时间来共享? [英] Why is std::mutex taking a long, highly irregular amount of time to be shared?

查看:380
本文介绍了为什么std :: mutex会花费很长时间,高度不规则的时间来共享?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这段代码演示了互斥锁在两个线程之间共享,但是一个线程几乎一直都在共享它.

This code demonstrates that the mutex is being shared between two threads, but one thread has it nearly all of the time.

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

#include <unistd.h>

int main ()
{
    std::mutex m;

    std::thread t ([&] ()
    {
        while (true)
        {
            {
                std::lock_guard <std::mutex> thread_lock (m);

                sleep (1); // or whatever
            }
            std::cerr << "#";
            std::cerr.flush ();
        }
    });

    while (true)
    {
        std::lock_guard <std::mutex> main_lock (m);
        std::cerr << ".";
        std::cerr.flush ();
    }
}

在Ubuntu 18.04 4.15.0-23-generic上与g ++ 7.3.0一起编译.

Compiled with g++ 7.3.0 on Ubuntu 18.04 4.15.0-23-generic.

输出是#.字符的混合,表明互斥对象正在共享,但是这种模式令人惊讶.通常是这样的:

The output is a mix of both # and . characters, showing that the mutex is being shared, but the pattern is surprising. Typically something like this:

.......#####..........................##################......................##

thread_lock可以长时间锁定互斥锁.几秒甚至数十秒后,main_lock(简短地)获得控制权,然后thread_lock将其收回并保留其使用期限.调用std::this_thread::yield()不会更改任何内容.

i.e. the thread_lock locks the mutex for a very long time. After several or even tens of seconds, the main_lock receives control (briefly) then the thread_lock gets it back and keeps it for ages. Calling std::this_thread::yield() doesn't change anything.

为什么这两个互斥锁获得锁的可能性不同,又该如何以平衡的方式共享该互斥锁?

Why are the two mutexes not equally likely to gain the lock, and how can I make the mutex be shared in a balanced fashion?

推荐答案

使std::mutex公平是有代价的.在C ++中,您不需要为自己不需要的东西付费.

Making std::mutex fair would have a cost. And in C++ you don't pay for what you don't ask for.

您可以编写一个锁定对象,使释放锁定的一方不能成为下一个获得该锁定对象的对象.更高级的是,您可以编写一个仅在其他人正在等待的情况下发生的情况.

You could write a locking object where the party releasing the lock cannot be the next one to get it. More advanced, you could write one where this only occurs if someone else is waiting.

这是在公平的互斥锁下未经测试的快速刺探:

Here is a quick, untested stab at a fair mutex:

struct fair_mutex {
  void lock() {
    auto l = internal_lock();
    lock(l);
  }
  void unlock() {
    auto l = internal_lock();
    in_use = false;
    if (waiting != 0) {
      loser=std::this_thread::get_id();
    } else {
      loser = {};
    }
    cv.notify_one();
  }
  bool try_lock() {
    auto l = internal_lock();
    if (in_use) return false;
    lock(l);
    return true;
  }
private:
  void lock(std::unique_lock<std::mutex>&l) {
    ++waiting;
    cv.wait( l, [&]{ return !in_use && std::this_thread::get_id() != loser; } );
    in_use = true;
    --waiting;
  }
  std::unique_lock<std::mutex> internal_lock() const {
    return std::unique_lock<std::mutex>(m);
  }
  mutable std::mutex m;
  std::condition_variable cv;
  std::thread::id loser;
  bool in_use = false;
  std::size_t waiting = 0;
};

这是公平的",因为如果有两个线程争用资源,则它们将轮流使用.如果有人在等待锁,那么放弃锁的任何人都不会再次抓住它.

it is "fair" in that if you have two threads contending over a resource, they will take turns. If someone is waiting on a lock, anyone giving up the lock won't grab it again.

但是,这是线程代码.所以我可能会读完它,但是我不相信我第一次尝试写任何东西.

This is, however, threading code. So I might read it over, but I wouldn't trust my first attempt to write anything.

您可以将其(以增加的成本)扩展到n公平(甚至是mega公平),如果最多有N个元素在等待,它们将轮到发布线程获得另一个机会之前.

You could extend this (at increasing cost) to be n-way fair (or even omega-fair) where if there are up to N elements waiting, they all get their turn before the releasing thread gets another chance.

这篇关于为什么std :: mutex会花费很长时间,高度不规则的时间来共享?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆