synchronized
in Java can guarantee thread-safety when accessing a shared object.
What about C++?
Use the following in C++:
#include <mutex>
std::mutex _mutex;
void f()
{
std::unique_lock<std::mutex> lock(_mutex);
// access your resource here.
}
Despite this question has been already answered, by the idea of this article I made my version of synchronized
keyword using just standard library (C++11) objects:
#include <mutex>
#define synchronized(m) \
for(std::unique_lock<std::recursive_mutex> lk(m); lk; lk.unlock())
You can test it like:
#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;
}
This is just an approximation of synchonized
keyword of Java but it works. Without it the sayHello
method of the previous example can be implemented as the accepted answer says:
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;
}
There is no keyword in C++03 equivalent to synchronized
in Java . But you can use Mutex to guarantee safety of thread.
C++ does not have built-in threading or synchronization (yet), you have to use libraries for that. Boost.Thread
is a good portable library that is designed to be compatible with the proposed threading facilities in C++0x.
In C++, I've implemented a macro that lets you simply do the following in order to synchronize access to a function or method:
// Define a function we want to synchronize.
void synchronizedFunction()
{
// Synchronize this function.
synchronized;
// We are now synchronized.
}
Here's how the macro is defined:
// 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))
This works for me with all three popular compilers { Windows, Clang, GCC }. This macro creates a unique static mutex variable for the function, and immediately locks it within the scope of that function. It could also be used within any scope, not just a function scope.
You can try this test program to prove that it works:
// 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;
}
When you run this program, you get the following output -- demonstrating that access to the function is serialized for each accessing thread. You will notice the one-second delay from when the function is entered and when the function has exited (both times). Because the function is now serialized, the test program will take approximately 2 seconds for this function to complete:
Thread 140737353824064 is entering.
Thread 140737353824064 is exiting.
Thread 140737257031424 is entering.
Thread 140737257031424 is exiting.
If you comment out the "synchronized;" statement, then you'll see that both threads enter the function almost simultaneously, producing something similar to the following output, or you may see text that stomps on top of itself. Because we are no longer synchronized, the test program will take approximately 1 second to complete instead of 2 seconds:
Thread 140737257031424 is entering.
Thread 140737353824064 is entering.
Thread 140737257031424 is exiting.
Thread 140737353824064 is exiting.
synchronized
macro in those getter and setter, you have undefined behavior again because we need to lock the same mutex. While the code looks protected, it is not. –
Piperpiperaceous © 2022 - 2024 — McMap. All rights reserved.