在 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
,表示接下来等待哪个线程。这在逻辑上等同于将要取的下一个数字
一个布尔值指示线程是否被允许继续以及何时完成,因此执行者知道何时调用下一个数字。
算法如下:
等待:
获取锁
记下 next_waiter
变量的值并递增它。
广播(通知所有)条件变量。
等待条件变量,直到布尔值为真且 released_thread
计数器等于步骤 2 中记下的值。
解除锁定
完成后,获取锁,将布尔值设置为false,广播条件变量,然后释放锁。
行政人员:
获取锁
等待条件变量,直到布尔值为假且 next_waiter
不等于 released_thread
。
递增 released_thread
并将布尔值设置为真。
广播条件变量。
转到步骤 2。
在这个 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
,表示接下来等待哪个线程。这在逻辑上等同于将要取的下一个数字
一个布尔值指示线程是否被允许继续以及何时完成,因此执行者知道何时调用下一个数字。
算法如下:
等待:
获取锁
记下
next_waiter
变量的值并递增它。广播(通知所有)条件变量。
等待条件变量,直到布尔值为真且
released_thread
计数器等于步骤 2 中记下的值。解除锁定
完成后,获取锁,将布尔值设置为false,广播条件变量,然后释放锁。
行政人员:
获取锁
等待条件变量,直到布尔值为假且
next_waiter
不等于released_thread
。递增
released_thread
并将布尔值设置为真。广播条件变量。
转到步骤 2。