c++多线程系列
c++多线程thread操作(五)unique_lock加锁
c++多线程thread操作(七)父进程获取子进程变量的结果
(终)c++多线程thread操作(十)多线程并行实现数据相加的和
1. 数据竞争问题:对共享资源的访问会出现杂乱无序的结果
void shared_print(string msg, int id) {
cout << "From" << id << " : " << msg << endl;// cout是可竞争资源, 需要同步cout
}
void func_1() {
for (int i = 0; i > -5; i--) {
shared_print("From t1: ",i); //
}
}
int main() {
thread t1(func_1);
for (int i = 0; i < 5; i++) {
shared_print("From main: ", i);
}
t1.join();
return 0;
}
2. 解决竞争问题:加上mutex锁
mutex mu;
void shared_print(string msg, int id) {
mu.lock();
cout << "From" << id << " : " << msg << endl;//如果这行发生了异常,mu锁将永远被锁住
mu.unlock();
}
void func_1() {
for (int i = 0; i > -5; i--) {
shared_print("From t1: ",i); //
}
}
int main() {
thread t1(func_1);
for (int i = 0; i < 5; i++) {
shared_print("From main: ", i);
}
t1.join();
return 0;
}
但如果mu.lock和mu.unlock之间抛出了异常,mu将永远被锁住!所有使用lock_guard锁来代替,只要lock_guard执行了析构函数,就会自动释放锁!
3. lock_guard代替mutex(建议不用Mutex,用lock_guard)
mutex mu;
void shared_print(string msg, int id) {
lock_guard<mutex> guard(mu);// guard析构时自动释放锁
cout << "From" << id << " : " << msg << endl;
}
但仍然有问题:cout是可竞争资源,多个线程可以共享使用,仍然达不到线程安全,考虑使用包装类加上ofstream流进行输出。
4. 类的实现,可作为模板使用:
#include <iostream>
#include <thread>
#include <string>
#include <mutex>
#include <fstream>
using namespace std;
class LofFile {
public:
LofFile() {
f.open("log.txt");
}
void shared_print(string msg, int id) {
lock_guard<mutex> guard(m_mutex);// guard析构时自动释放锁
f << "From" << id << " : " << msg << endl;
}
//ofstream&GetStream() { return f; }// 这个是不安全的,f会暴露在函数外
//void processf(void fun(ofstream&)) {
// fun(f);// f也会暴露在类外,会造成线程不安全
//}
private:
mutex m_mutex;
ofstream f;// 线程安全的f
};
void func_1(LofFile&log) {
for (int i = 0; i > -10; i--) {
log.shared_print("From t1: ", i);
}
}
int main() {
LofFile log;
thread t1(func_1,ref(log));
for (int i = 0; i < 10; i++) {
log.shared_print("From main: ", i);
}
t1.join();
return 0;
}
但要注意,ofstream不能暴露在类的外面,否则不能实现完全线程安全。如上述代码的注释!