struct Counter {
int value;
void increment(){
++value;
}
};
这并没什么稀奇的,下面让我们来启动一些线程来增加计数器的计数吧。
int main(){
Counter counter;
std::vector<std::thread> threads;
for(int i = 0; i < 5; ++i){
threads.push_back(std::thread([&counter](){
for(int i = 0; i < 100; ++i){
counter.increment();
}
}));
}
for(auto& thread : threads){
thread.join();
}
std::cout << counter.value << std::endl;
return 0;
}
442
500
477
400
422
487
-
Semaphores
-
Atomic references
-
Monitors
-
Condition codes
-
Compare and swap
-
etc.
struct Counter {
std::mutex mutex;
int value;
Counter() : value(0) {}
void increment(){
mutex.lock();
++value;
mutex.unlock();
}
};
struct Counter {
int value;
Counter() : value(0) {}
void increment(){
++value;
}
void decrement(){
if(value == 0){
throw "Value cannot be less than 0";
}
--value;
}
};
假设你想在不更改上述代码的前提下为其提供线程安全性,那么你需要为其创建一个
Wrapper
类:
struct ConcurrentCounter {
std::mutex mutex;
Counter counter;
void increment(){
mutex.lock();
counter.increment();
mutex.unlock();
}
void decrement(){
mutex.lock();
counter.decrement();
mutex.unlock();
}
};
这个 Wrapper 将在大多数情况下正常工作,然而一旦 decrement() 抛出异常,你就遇到大麻烦了,当异常被抛出时, unlock() 函数将不会被调用,这将导致本线程获得的锁不被释放,你的程序也就顺理成章的被永久阻塞了。为了修复这一问题,你需要使用 try/catch 块以保证在抛出任何异常之前释放获得的锁。
void decrement(){
mutex.lock();
try {
counter.decrement();
} catch (std::string e){
mutex.unlock();
throw e;
}
mutex.unlock();
}
struct ConcurrentSafeCounter {
std::mutex mutex;
Counter counter;
void increment(){
std::lock_guard<std::mutex> guard(mutex);
counter.increment();
}
void decrement(){
std::lock_guard<std::mutex> guard(mutex);
counter.decrement();
}
};