这个简单的 Mutex 没有任何作用
This simple Mutex does not have any effect
我正在尝试学习多线程的基础知识。下面的示例来自“多处理器编程艺术”一书,其中有(Java):
class Counter
{
private long value;
private Lock lock;
public long getAndIncrement()
{
lock.lock();
try
{
long temp = value;
value = temp + 1;
return temp;
}
finally
{
lock.unlock();
}
}
}
java 代码结束。书中说上面显示的“lock() 和 unlock()”将为这个共享计数器实现添加互斥。 (我无法 运行 这个 java 自己编写代码,而且我认为应该返回“value”而不是“temp”。)
当我尝试这个简单的示例(在我可以尝试的 C++ 中)时,我的互斥体没有做任何事情。我可以删除它,结果是一样的。
C++代码:
#include <iostream>
#include <thread>
#include <mutex>
class Counter
{
public:
Counter(int v)
: value(v)
{}
int getAndIncrement()
{
std::lock_guard<std::mutex> lk(m);
return value++;
}
void show() const
{
std::cout << "value = " << value << '\n';
}
private:
int value;
std::mutex m;
};
int main()
{
Counter c1(1);
std::thread t1(&Counter::getAndIncrement, &c1);
t1.detach();
c1.show(); // 1 or 2
std::thread t2(&Counter::getAndIncrement, &c1);
t2.detach();
c1.show(); // 1 or 2
//int n = c1.getAndIncrement();
//std::cout << n << '\n'; // 1 or 2 or 3. never 4
c1.getAndIncrement();
c1.show(); //2, 3 and sometimes 4
}
注释显示我 运行 代码时的输出。我的互斥体没有效果。
任何指南将不胜感激。
谢谢。
互斥量的作用应该是确保没有两个线程同时读取或写入成员(只读就可以)。在您的代码中情况并非如此,因为同时一个线程锁定了互斥锁并写入主线程可能调用的成员 show
。您需要保护任何访问权限:
void show() const
{
std::lock_guard<std::mutex> lk(m);
std::cout << "value = " << value << '\n';
}
那么你的代码是好的,你观察到的输出是预期的。
您正在启动 2 个线程,您无法知道这些线程是先从成员写入还是先从成员读取。
可能的顺序是:
thread t1 writes
main calls show 2
main calls show 2
main increments
main calls show 3
thread t2 writes
另一个可能的顺序是:
main calls show 1
main calls show 1
thread t2 writes
thread t1 writes
main increments
main calls show 4
互斥锁只保护对成员的并发访问。您可以确定这将按顺序发生:
main calls show
main calls show
main increments
main calls show
如果您希望事情在不同线程之间也以特定顺序发生,您需要添加某种同步(例如,条件变量)。尽管对于您的简单示例,这基本上对应于没有并行性,并且添加线程只会增加开销。
So final value of "value" is not supposed to be 4
让我们从您的代码中删除 detach
并添加一些 join
:
int main()
{
Counter c1(1);
std::thread t1(&Counter::getAndIncrement, &c1);
c1.show(); // 1 or 2
std::thread t2(&Counter::getAndIncrement, &c1);
c1.show(); // 1 or 2 or 3
c1.getAndIncrement();
c1.show(); // 2, 3 or 4
t1.join();
t2.join();
c1.show(); // definitely 4 !!!
}
join
等待线程完成。即:我们可以确定到 join
returns 时,线程已经从 getAndIncrement
返回。最后的 show
肯定会打印 4
。在一个更简单的例子中:
int main()
{
Counter c1(1);
std::thread t1(&Counter::getAndIncrement, &c1);
c1.show(); // 1 or 2
t1.join();
c1.show(); // 2
}
PS:我还不能完全确定你的误会到底是什么is/was。考虑到多线程不仅仅是单线程+线程。它是设计的一部分。通常会使用不同的算法或数据结构 must/should。
我正在尝试学习多线程的基础知识。下面的示例来自“多处理器编程艺术”一书,其中有(Java):
class Counter
{
private long value;
private Lock lock;
public long getAndIncrement()
{
lock.lock();
try
{
long temp = value;
value = temp + 1;
return temp;
}
finally
{
lock.unlock();
}
}
}
java 代码结束。书中说上面显示的“lock() 和 unlock()”将为这个共享计数器实现添加互斥。 (我无法 运行 这个 java 自己编写代码,而且我认为应该返回“value”而不是“temp”。)
当我尝试这个简单的示例(在我可以尝试的 C++ 中)时,我的互斥体没有做任何事情。我可以删除它,结果是一样的。 C++代码:
#include <iostream>
#include <thread>
#include <mutex>
class Counter
{
public:
Counter(int v)
: value(v)
{}
int getAndIncrement()
{
std::lock_guard<std::mutex> lk(m);
return value++;
}
void show() const
{
std::cout << "value = " << value << '\n';
}
private:
int value;
std::mutex m;
};
int main()
{
Counter c1(1);
std::thread t1(&Counter::getAndIncrement, &c1);
t1.detach();
c1.show(); // 1 or 2
std::thread t2(&Counter::getAndIncrement, &c1);
t2.detach();
c1.show(); // 1 or 2
//int n = c1.getAndIncrement();
//std::cout << n << '\n'; // 1 or 2 or 3. never 4
c1.getAndIncrement();
c1.show(); //2, 3 and sometimes 4
}
注释显示我 运行 代码时的输出。我的互斥体没有效果。 任何指南将不胜感激。 谢谢。
互斥量的作用应该是确保没有两个线程同时读取或写入成员(只读就可以)。在您的代码中情况并非如此,因为同时一个线程锁定了互斥锁并写入主线程可能调用的成员 show
。您需要保护任何访问权限:
void show() const
{
std::lock_guard<std::mutex> lk(m);
std::cout << "value = " << value << '\n';
}
那么你的代码是好的,你观察到的输出是预期的。
您正在启动 2 个线程,您无法知道这些线程是先从成员写入还是先从成员读取。
可能的顺序是:
thread t1 writes
main calls show 2
main calls show 2
main increments
main calls show 3
thread t2 writes
另一个可能的顺序是:
main calls show 1
main calls show 1
thread t2 writes
thread t1 writes
main increments
main calls show 4
互斥锁只保护对成员的并发访问。您可以确定这将按顺序发生:
main calls show
main calls show
main increments
main calls show
如果您希望事情在不同线程之间也以特定顺序发生,您需要添加某种同步(例如,条件变量)。尽管对于您的简单示例,这基本上对应于没有并行性,并且添加线程只会增加开销。
So final value of "value" is not supposed to be 4
让我们从您的代码中删除 detach
并添加一些 join
:
int main()
{
Counter c1(1);
std::thread t1(&Counter::getAndIncrement, &c1);
c1.show(); // 1 or 2
std::thread t2(&Counter::getAndIncrement, &c1);
c1.show(); // 1 or 2 or 3
c1.getAndIncrement();
c1.show(); // 2, 3 or 4
t1.join();
t2.join();
c1.show(); // definitely 4 !!!
}
join
等待线程完成。即:我们可以确定到 join
returns 时,线程已经从 getAndIncrement
返回。最后的 show
肯定会打印 4
。在一个更简单的例子中:
int main()
{
Counter c1(1);
std::thread t1(&Counter::getAndIncrement, &c1);
c1.show(); // 1 or 2
t1.join();
c1.show(); // 2
}
PS:我还不能完全确定你的误会到底是什么is/was。考虑到多线程不仅仅是单线程+线程。它是设计的一部分。通常会使用不同的算法或数据结构 must/should。