Anthony Williams がチャプター 6.2.3 C++ Concurrency in Action で紹介したきめの細かいロック キューを次に示します。
/*
pop only need lock head_mutex and a small section of tail_mutex,push only need
tail_mutex mutex.maximum container concurrency.
*/
template<typename T> class threadsafe_queue
{
private:
struct node
{
std::shared_ptr<T> data;
std::unique_ptr<node> next;
}
std::mutex head_mutex; //when change the head lock it.
std::unique_ptr<node> head;
std::mutex tail_mutex; //when change the tail lock it.
node* tail;
std::condition_variable data_cond;
node* get_tail()
{
std::lock_guard<std::mutex> tail_lock(tail_mutex);
return tail;
}
public:
/*
create a dummy node
*/
threadsafe_queue():
head(new node),tail(head.get())
{}
std::shared_ptr<T> wait_and_pop()
{
std::unique_lock<std::mutex> head_lock;
data_cond.wait(head_lock,[&]{return head.get()!=get_tail();}); //#1
std::unique_ptr<node> old_head=std::move(head);
head=std::move(old_head->next);
return old_head;
}
void push(T new_value)
{
std::shared_ptr<T> new_data(
std::make_shared<T>(std::move(new_value)));
std::unique_ptr<node> p(new node);
{
std::lock_guard<std::mutex> tail_lock(tail_mutex);
tail->data=new_data;
node* const new_tail=p.get();
tail->next=std::move(p);
tail=new_tail;
}
data_cond.notify_one();
}
}
状況は次のとおりです。2 つのスレッド (thread1
およびthread2
) があります。thread1
を行っておりwait_and_pop
、thread2
を行っていpush
ます。キューは空です。
thread1
は #2 にあり、head.get()!=get_tail()
以前にチェック済みdata_cond.wait()
です。この時点で、その CPU 期間は終了していました。thread2
始まります。
thread2
push
機能を終えましたdata_cond.notify_one()
。thread1
再び始まります。
今thread1
始まりますがdata_cond.wait()
、それは永遠に待ちます。
この状況が発生する可能性はありますか?その場合、このコンテナを修正するにはどうすればよいですか?