这是我的问题。我有几个线程修改了struture的attributs,我有一个读取结构的线程。我如何确定我正在读取的值不会被其他线程更改?在我的情况下,属性只能由一个线程修改。
例:
typedef struct
{
int a;
double b;
} data;
data glob;
int main()
{
thread reader([]()
{
while(1)
{
sleep(1s);
cout << glob;
}
});
thread writer1([]()
{
while(1)
glob.a++;
});
thread writer2([]()
{
while(1)
glob.b++;
});
int i;
cin >>i;
}
然后,我怎么能确定当我读取glob时,它不会被writer1和writer2修改?
答案 0 :(得分:4)
#include <thread>
#include <atomic>
#include <iostream>
#include<chrono>
typedef struct
{
std::atomic_int a;
std::atomic<double> b;
} data;
data glob;
int main()
{
glob.a.store(0);//store data in the atomic variable
glob.b.store(0.0);
std::thread reader([]()
{
while (1)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << glob.a.load() << " " << glob.b.load() << std::endl; //get the value of the variable
}
});
std::thread writer1([]()
{
while (1)
glob.a++;
});
std::thread writer2([]()
{
while (1)
glob.b.store(glob.b.load() +1); // std::atomic<double> has no member operator++ so have to improvise
});
int i;
std::cin >> i;
}
对于使用<atomic>
进行不可分割的访问和写入操作的问题,这是一个简单的解决方案。
答案 1 :(得分:0)
使用互斥锁,一旦你了解它就非常简单。
http://en.cppreference.com/w/cpp/thread/mutex
http://en.cppreference.com/w/cpp/thread/lock_guard
代码示例:未经过测试可能会导致datarace和/或死锁
#include <thread>
#inclue <mutex>
typedef struct
{
int a;
double b;
} data;
data glob;
mutex mymutex;
int main()
{
thread reader([]()
{
while(1)
{
mymutex.lock();
sleep(1s);
cout << glob;
mymutex.unlock();
}
});
thread writer1([]()
{
while(1)
mymutex.lock();
glob.a++;
mymutex.unlock();
});
thread writer2([]()
{
while(1)
mymutex.lock();
glob.b++;
mymutex.unlock();
});
int i;
cin >>i;
}
因此,这会在更改glob时锁定互斥锁,并在互连完成更改后解锁互斥锁。当互斥锁被锁定时,另一个尝试访问该互斥锁的线程将无法执行,因此将等待一段时间,然后再次尝试。最终它会抓住它并能够自己锁定它。然后另一个线程将不得不等待它解锁。
我链接的lock_guard是一种使用互斥锁的更安全的方法,但只能在函数中使用。你把它放在函数的开头,然后它将保持锁定直到函数返回。这意味着您不必确保在函数的每个返回路径上解锁互斥锁,因为这是自动完成的。
Mutex确实存在死锁问题。当您锁定互斥锁,然后在互斥锁解锁之前尝试再次在同一线程中锁定互斥锁时,会发生这种情况。它将永远等待无法解锁,其他线程也无法继续。如果您从互斥区域调用函数,则简单的解决方案是使用多个互斥锁。