如何决定我需要多少个互斥体?

How to decide how many mutexes do I require?

这里我为 2 个条件变量使用了 2 个互斥量。如何判断一个互斥量是否足够或需要单独的互斥量?

来源:

#include "thread_class.h"

#include <unistd.h>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <iostream>

// Thread_manager class: ***************************************************************************************************************
std::queue<int> queue_m;

std::mutex mutex_k;

bool watch;

std::mutex mutex_x;
std::mutex mutex_y;

std::condition_variable cv_x;
std::condition_variable cv_y;

ThreadManager::ThreadManager() : obj_thread_B_( &B::Run, &obj_class_B_),
                                 obj_thread_A_( &A::Run, &obj_class_A_ )
{
    watch = false;
}

ThreadManager::~ThreadManager()
{
    obj_thread_A_.join();
    obj_thread_B_.join();
}

void A::Run()
{
    while( 1 )
    {
        std::unique_lock<std::mutex> lk( mutex_x );
        while (watch == false)
            cv_x.wait( lk );

        std::cout << "\nA class\n";

        someint++;
        queue_m.push( someint );

        cv_y.notify_all();

        // some time consuming operation
        for (int t = 0; t < 1000000; t++)
        {
        }
    }
}

void B::Run()
{
    while( 1 )
    {
        std::cout << "\nB class\n";

        if (queue_m.size() > 0)
        {
            int temp = queue_m.front();
            std::cout << "\nTaken out: " << temp;
            queue_m.pop();

            cv_x.notify_all();
        }
        else
        {
            std::unique_lock<std::mutex> lk( mutex_y );
            watch = true;

            cv_x.notify_all();

            cv_y.wait( lk );
        }
     }
}

这取决于您进程中 race condition 的总数。根据您流程中的不同 race condition,您将决定处理所有 race conditions 真正需要的互斥体数量。请阅读以下答案,这将有助于您了解 race condition.

What is a race condition?

:这取决于你有多少比赛条件。这里有一些更多的细节来确定这一点。

  1. 拿出一张纸。在右侧,列出您要保证任何线程在使用时独占访问的所有 受保护资源
  2. 在页面左侧,列出页面中可能需要这些资源的所有 线程。如果你只知道它将> 1个线程,你可以只写“线程1”和“线程2”来表示无限数量的线程。
  3. 从左边的每个线程画一个箭头到右边它需要的所有资源。
  4. 如果有多个箭头指向一个资源,请圈出右侧的所有箭头连接点。计算圈数。这就是该模块的竞争条件数量,这就是您需要的独立互斥体数量。

我刚刚起草的例子。此示例具有 3 个竞争条件(注意 3 个圆圈),因此需要 3 个单独的互斥锁:

  1. 现在评估左边:你能通过将多个线程的功能组合到一个单个线程中来删除左边的任何线程吗?如果是这样,就这样做。相反:是否需要将任何线程拆分为 2 个或更多线程以分离功能?如果是这样,就这样做。
  2. 评估右边:你能把右边的任何资源组合成1,用单个互斥体保护吗?例如:尝试将“UART 写入”和“UART 读取”组合成一个 单一受保护资源。 这行得通吗?那么,如果“只读线程”和“只写线程”必须分别同时并行读取和写入(即:它们不能等待彼此并连续进行),然后不!这行不通!他们必须保持独立的资源!但是,如果他们可以根据您的项目和设计相互等待并连续执行这些操作,那么可以!您可以组合这两个东西,现在用 1 个互斥锁保护它们,并删除额外的互斥锁。
  3. 一旦您评估了左侧和右侧,根据您的设计需要组合或拆分线程和资源,请重复上面的步骤 3 和 4。数圈数。那就是你有多少竞争条件,因此你的设计需要多少不同的互斥量。

注意你在这里有多少回旋余地和控制权。其中很多取决于 您的特定架构设计 。你是建筑师和设计师。您可能会想出与其他人不同的解决方案和互斥体数量,并且每种设计都存在权衡和优缺点。这可能很好。 请记住:您是设计师,设计可以有所不同。有时候没有完美的设计,你只需要做出权衡。尽管如此,上述有条不紊的过程将帮助您确定您的特定设计需要多少个互斥体。