一个互斥锁与多个互斥锁。线程池用哪个好?
One mutex vs Multiple mutexes. Which one is better for the thread pool?
这里的例子,只是想保护iData
保证只有一个线程同时访问它
struct myData;
myData iData;
方法一,调用函数内部互斥(可创建多个互斥):
void _proceedTest(myData &data)
{
std::mutex mtx;
std::unique_lock<std::mutex> lk(mtx);
modifyData(data);
lk.unlock;
}
int const nMaxThreads = std::thread::hardware_concurrency();
vector<std::thread> threads;
for (int iThread = 0; iThread < nMaxThreads; ++iThread)
{
threads.push_back(std::thread(_proceedTest, iData));
}
for (auto& th : threads) th.join();
方法二,只使用一个互斥量:
void _proceedTest(myData &data, std::mutex &mtx)
{
std::unique_lock<std::mutex> lk(mtx);
modifyData(data);
lk.unlock;
}
std::mutex mtx;
int const nMaxThreads = std::thread::hardware_concurrency();
vector<std::thread> threads;
for (int iThread = 0; iThread < nMaxThreads; ++iThread)
{
threads.push_back(std::thread(_proceedTest, iData, mtx));
}
for (auto& th : threads) th.join();
- 我想确保方法一(多互斥锁)确保只有一个线程可以同时访问iData。
- 如果方法 1 正确,不确定方法 1 是否优于方法 2?
谢谢!
- I want to make sure that the Method 1 (multiple mutexes) ensures that only one thread can visit the iData at the same time.
您的第一个示例在堆栈上创建了一个本地互斥变量,它不会与其他线程共享。所以完全没有用。
它不能保证对 iData
.
的独占访问
- If Method 1 is correct, not sure Method 1 is better of Method 2?
不正确。
一旦您离开 _proceedTest 范围,版本 1 中的互斥量就会超出范围,锁定这样的互斥量是没有意义的,因为其他线程永远无法访问它。
在第二个版本中,多个线程可以共享互斥量(只要它不超出范围,例如作为 class 成员),这样一个线程可以锁定它,另一个线程可以看到它已被锁定(并且也无法锁定它,因此称为互斥术语)。
方法 1 仅在您创建互斥变量 static
.
时有效
void _proceedTest(myData &data)
{
static std::mutex mtx;
std::unique_lock<std::mutex> lk(mtx);
modifyData(data);
lk.unlock;
}
这将使 mtx
被所有进入 _proceedTest
的线程共享。
由于 static
函数范围变量仅对函数的用户可见,因此对于传入的 data
来说,它并不是真正足够的锁。这是因为可以想象多个线程可能正在调用每个想要操作的不同函数 data
.
因此,尽管方法 1 可以挽救,但方法 2 仍然更好,即使锁和数据之间的内聚性较弱。
其他答案在技术层面上是正确的,但是缺少一个重要的与语言无关的东西:你总是喜欢尽量减少不同mutexes/locks/ ... !
因为:一旦你有超过 一个 线程需要获取的东西才能做某事(然后释放所有获取的锁) order 变得至关重要。
当你有 两个 锁时,你必须使用不同的代码片段,例如:
getLockA() {
getLockB() {
do something
release B
release A
和
getLockB() {
getLockA() {
您可以很快 运行 进入死锁 - 因为两个 threads/processes 可以每个获得一个锁 - 然后它们都被卡住,等待另一个释放它的锁。当然 - 在查看上面的示例时 "you would never make a mistake, and always go A first then B"。但是,如果这些锁存在于应用程序的完全不同部分怎么办?而且它们不是通过相同的方法或 class 获取的,而是在 3、5 次嵌套方法调用过程中获取的?
因此:当您可以用一把锁解决问题时 - 只使用 一把 锁!完成某件事所需的锁越多,陷入死锁的风险就越高。
这里的例子,只是想保护iData
保证只有一个线程同时访问它
struct myData;
myData iData;
方法一,调用函数内部互斥(可创建多个互斥):
void _proceedTest(myData &data)
{
std::mutex mtx;
std::unique_lock<std::mutex> lk(mtx);
modifyData(data);
lk.unlock;
}
int const nMaxThreads = std::thread::hardware_concurrency();
vector<std::thread> threads;
for (int iThread = 0; iThread < nMaxThreads; ++iThread)
{
threads.push_back(std::thread(_proceedTest, iData));
}
for (auto& th : threads) th.join();
方法二,只使用一个互斥量:
void _proceedTest(myData &data, std::mutex &mtx)
{
std::unique_lock<std::mutex> lk(mtx);
modifyData(data);
lk.unlock;
}
std::mutex mtx;
int const nMaxThreads = std::thread::hardware_concurrency();
vector<std::thread> threads;
for (int iThread = 0; iThread < nMaxThreads; ++iThread)
{
threads.push_back(std::thread(_proceedTest, iData, mtx));
}
for (auto& th : threads) th.join();
- 我想确保方法一(多互斥锁)确保只有一个线程可以同时访问iData。
- 如果方法 1 正确,不确定方法 1 是否优于方法 2? 谢谢!
- I want to make sure that the Method 1 (multiple mutexes) ensures that only one thread can visit the iData at the same time.
您的第一个示例在堆栈上创建了一个本地互斥变量,它不会与其他线程共享。所以完全没有用。
它不能保证对 iData
.
- If Method 1 is correct, not sure Method 1 is better of Method 2?
不正确。
一旦您离开 _proceedTest 范围,版本 1 中的互斥量就会超出范围,锁定这样的互斥量是没有意义的,因为其他线程永远无法访问它。
在第二个版本中,多个线程可以共享互斥量(只要它不超出范围,例如作为 class 成员),这样一个线程可以锁定它,另一个线程可以看到它已被锁定(并且也无法锁定它,因此称为互斥术语)。
方法 1 仅在您创建互斥变量 static
.
void _proceedTest(myData &data)
{
static std::mutex mtx;
std::unique_lock<std::mutex> lk(mtx);
modifyData(data);
lk.unlock;
}
这将使 mtx
被所有进入 _proceedTest
的线程共享。
由于 static
函数范围变量仅对函数的用户可见,因此对于传入的 data
来说,它并不是真正足够的锁。这是因为可以想象多个线程可能正在调用每个想要操作的不同函数 data
.
因此,尽管方法 1 可以挽救,但方法 2 仍然更好,即使锁和数据之间的内聚性较弱。
其他答案在技术层面上是正确的,但是缺少一个重要的与语言无关的东西:你总是喜欢尽量减少不同mutexes/locks/ ... !
因为:一旦你有超过 一个 线程需要获取的东西才能做某事(然后释放所有获取的锁) order 变得至关重要。
当你有 两个 锁时,你必须使用不同的代码片段,例如:
getLockA() {
getLockB() {
do something
release B
release A
和
getLockB() {
getLockA() {
您可以很快 运行 进入死锁 - 因为两个 threads/processes 可以每个获得一个锁 - 然后它们都被卡住,等待另一个释放它的锁。当然 - 在查看上面的示例时 "you would never make a mistake, and always go A first then B"。但是,如果这些锁存在于应用程序的完全不同部分怎么办?而且它们不是通过相同的方法或 class 获取的,而是在 3、5 次嵌套方法调用过程中获取的?
因此:当您可以用一把锁解决问题时 - 只使用 一把 锁!完成某件事所需的锁越多,陷入死锁的风险就越高。