synchronized
可以保证访问共享对象时的线程安全。
那么 C++ 呢?
在 C++ 中使用以下内容:
#include <mutex>
std::mutex _mutex;
void f()
{
std::unique_lock<std::mutex> lock(_mutex);
// access your resource here.
}
尽管这个问题已经得到解答,但根据this文章的想法,我仅使用标准库(C ++ 11)对象制作了我的
synchronized
关键字版本:
#include <mutex>
#define synchronized(m) \
for(std::unique_lock<std::recursive_mutex> lk(m); lk; lk.unlock())
您可以像这样测试它:
#include <iostream>
#include <iomanip>
#include <mutex>
#include <thread>
#include <vector>
#define synchronized(m) \
for(std::unique_lock<std::recursive_mutex> lk(m); lk; lk.unlock())
class Test {
std::recursive_mutex m_mutex;
public:
void sayHello(int n) {
synchronized(m_mutex) {
std::cout << "Hello! My number is: ";
std::cout << std::setw(2) << n << std::endl;
}
}
};
int main() {
Test test;
std::vector<std::thread> threads;
std::cout << "Test started..." << std::endl;
for(int i = 0; i < 10; ++i)
threads.push_back(std::thread([i, &test]() {
for(int j = 0; j < 10; ++j) {
test.sayHello((i * 10) + j);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}));
for(auto& t : threads) t.join();
std::cout << "Test finished!" << std::endl;
return 0;
}
这只是 Java 的
synchonized
关键字的近似值,但它是有效的。如果没有它,上一个示例的 sayHello
方法可以实现为 接受的答案 说:
void sayHello(unsigned int n) {
std::unique_lock<std::recursive_mutex> lk(m_mutex);
std::cout << "Hello! My number is: ";
std::cout << std::setw(2) << n << std::endl;
}
C++03 中没有相当于 Java 中的
synchronized
的关键字。但是可以使用Mutex来保证线程的安全。
// Under the hood, we use a mutex to synchronize.
#include <mutex>
// Create a synchronized keyword.
#define CONCAT_INNER(a, b) a##b
#define CONCAT(a, b) CONCAT_INNER(a, b)
#define UNIQUE_NAME(base) CONCAT(base, __LINE__)
#define synchronized static std::mutex UNIQUE_NAME(syncMutex); std::unique_lock<std::mutex> syncLock(UNIQUE_NAME(syncMutex))
这对我来说适用于所有三种流行的编译器{Windows、Clang、GCC}。该宏为该函数创建一个唯一的静态互斥变量,并立即将其锁定在该函数的范围内。它也可以在任何范围内使用,而不仅仅是函数范围。要在函数中使用它,只需执行以下操作:
// Define a function we want to synchronize.
void synchronizedFunction()
{
// Synchronize this function.
synchronized;
// We are now synchronized.
}
您可以尝试这个测试程序来证明它有效:
// Under the hood, we use a mutex to synchronize.
#include <mutex>
// Create a synchronized keyword.
#define CONCAT_INNER(a, b) a##b
#define CONCAT(a, b) CONCAT_INNER(a, b)
#define UNIQUE_NAME(base) CONCAT(base, __LINE__)
#define synchronized static std::mutex UNIQUE_NAME(syncMutex); std::unique_lock<std::mutex> syncLock(UNIQUE_NAME(syncMutex))
// For our test program below.
#include <iostream>
#include <thread>
// Define a function we want to synchronize.
void synchronizedFunction()
{
// Synchronize this function.
synchronized;
// Print something, then sleep for 1 second, then print something else.
// If we're synchronized, these two messages will appear back-to-back.
// If we're not synchronized, these messages display in an uncontrolled fashion.
std::cout << "Thread " << std::this_thread::get_id() << " is entering." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Thread " << std::this_thread::get_id() << " is exiting." << std::endl;
}
// A simple test program that will access our synchronized function from 2 asynchronous threads.
int main()
{
// Construct a new thread and have it call our synchronized function.
std::thread newThread(synchronizedFunction);
// In our main thread, also call our synchronized function.
synchronizedFunction();
// Join both threads before exiting.
newThread.join();
// Exit.
return 0;
}
当您运行此程序时,您将获得以下输出 - 演示对每个访问线程的函数的访问都是序列化的。您会注意到从进入函数到退出函数(两次)都有一秒的延迟。由于该函数现已序列化,因此测试程序大约需要 2 秒才能完成该函数:
Thread 140737353824064 is entering.
Thread 140737353824064 is exiting.
Thread 140737257031424 is entering.
Thread 140737257031424 is exiting.
如果注释掉“synchronized;”语句,那么您将看到两个线程同时进入该函数,产生类似于以下输出的内容,或者您可能会看到文本踩在其自身之上。因为我们不再同步,所以测试程序大约需要 1 秒才能完成,而不是 2 秒:
Thread 140737257031424 is entering.
Thread 140737353824064 is entering.
Thread 140737257031424 is exiting.
Thread 140737353824064 is exiting.