我正在尝试使用条件变量和唯一锁来创建一个线程安全列表。但是,我遇到了一些问题,似乎列表操作不是线程安全的。
我创建了一个 atomic_flag
来测试它是否是线程安全的。
基本上,当我操作列表时,我将首先检查原子标志是否已设置,并在列表操作完成时清除原子标志。
在我看来,原子标志在互斥保护下运行,因此每当我 test_and_set
原子标志时,我都应该看到初始值应该是假的,但是当我运行测试代码时,我发现它并非如此。
任何人都可以帮助我并指出代码有什么问题,为什么列表操作对于条件变量的保护不是线程安全的?
由于 测试代码如下:
using namespace std;
//list element
class myitem
{
public:
myitem() { val = -1; };
myitem(int n, int c){ val = n; chr = c; };
int val;
char chr;
};
// mutex and condition variable to protect the list.
std::mutex mymtx;
condition_variable mycv;
// the list to be protected
std::list<myitem> mylist;
// the atomic flag to test.
std::atomic_flag testlk = ATOMIC_FLAG_INIT;
void datagenthread(char c)
{
int n = 10*1000*1000;
while(n >0)
{
myitem item(n, c);
{
unique_lock<mutex> lk(mymtx); // get the lock
if( testlk.test_and_set() != false) { // test the atomic flag
cout<<"error in thread"<<c<<" for test lock"<<endl;
}
mylist.push_back(item);
testlk.clear(); // clear the atomic before unlock.
}
mycv.notify_one();
n--;
}
}
void datareadthread()
{
int count = 0;
int readc = 0;
while ( count <2) {
{
unique_lock<mutex> lk(mymtx); // acquire lock
while ( mylist.size() <= 0) {
mycv.wait(lk); // block until the thread get notified and get lock again.
}
if( testlk.test_and_set()!= false) {// test the atomic flag.
cout<<"error in reader thread"<<endl;
}
myitem readitem;
readitem = mylist.front();
mylist.pop_front();
readc++;
if ( readitem.val == 1)
{
cout<<" get last one last item form a thread,"<<endl;
count++;
}
testlk.clear(); // clear the atomic flag before unlock
}//unique_lock destruct
}//end while
}
int main()
{
std::thread cons( datareadthread);
std::thread gen1( datagenthread, 'a');
std::thread gen2( datagenthread, 'b');
gen1.join();
gen2.join();
cons.join();
return 0;
}
答案 0 :(得分:0)
testlk
默认构造函数将其初始化为未指定的状态,因此在第一次迭代时,初始值为false
以外的值。你应该用清除状态初始化它,如下所示:
std::atomic_flag testlk = ATOMIC_FLAG_INIT;
答案 1 :(得分:0)
我找到了原因,似乎我链接了一些错误的libs导致mutex / condition_var无法正常工作。