在 C++ 中为线程提供临界区

providing critical section for threads in c++

在这个 c++ 程序中,我创建了 10 个线程,它们相互竞争以获得关键 section.For 这意味着我正在使用如下条件变量 code.The 此程序中的调度程序将授予一个线程一次进入critical section.But 有一个微妙的问题。当调度程序授予线程进入时,它将设置 ready_pipe 变量为真。如果此时(在consumer 设置ready_pipe=flase 之前)有一个新线程到来,新线程将未经许可越过临界区。

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

std::condition_variable con_var_pipe;
bool ready_pipe = false;
std::mutex pipe_mutex;

bool critical_section_is_free=true;

void dispatcher()
{

    while(true)
    {

        if(critical_section_is_free)
        {
            critical_section_is_free=false;

            // send signal to a thread to enter critical section
            std::lock_guard<std::mutex> lk(pipe_mutex);
            ready_pipe = true;
            con_var_pipe.notify_one();

        }
    }
}


void consumer()
    {
    std::unique_lock<std::mutex> lk(pipe_mutex);

    /* The Problem is Here at below line.When a new thread comes, 
      it will pass through this block because it see ready_pipe is true!!!*/

    con_var_pipe.wait(lk, [] {return ready_pipe;});

    /// critical section starts
    ready_pipe=false;
    /// here accessing pipe is occurring .

    /// critical section ends
    critical_section_is_free=true;


}

 int main()
    {
    std::thread allThreads[10];

    for(int i = 0 ; i<10 ; i++)
    {
        allThreads[i]=std::thread(consumer);
    }

    thread disp(dispatcher);

    for(int i = 0 ; i< 6 ; i++)
    {
        allThreads[i].join();
    }

    disp.join();

    return 0;
}

此外,由于dispatcher函数中的while(true)语句导致忙等待,这段代码也有不足之处。

所以问题是:

1-新线程到来时如何创建互斥

2-如何避免在 dispatcher() 函数中忙等待。

3-以及当线程进入并在 wait() 中注册时如何按顺序服务线程。

只需使用两个计数器和一个布尔值即可实现基本的 "take a number" 方案。

一个计数器 released_thread 指示哪个线程可以继续。这在逻辑上等同于 "now serving" 指标。

另一个,next_waiter,表示接下来等待哪个线程。这在逻辑上等同于将要取的下一个数字

一个布尔值指示线程是否被允许继续以及何时完成,因此执行者知道何时调用下一个数字。

算法如下:

等待:

  1. 获取锁

  2. 记下 next_waiter 变量的值并递增它。

  3. 广播(通知所有)条件变量。

  4. 等待条件变量,直到布尔值为真且 released_thread 计数器等于步骤 2 中记下的值。

  5. 解除锁定

  6. 完成后,获取锁,将布尔值设置为false,广播条件变量,然后释放锁。

行政人员:

  1. 获取锁

  2. 等待条件变量,直到布尔值为假且 next_waiter 不等于 released_thread

  3. 递增 released_thread 并将布尔值设置为真。

  4. 广播条件变量。

  5. 转到步骤 2。