公众平台是什么,网站优化及推广,网站建设网站建设的网络,高要网站制作目录std::unique_lock类模板仅调用一次线程局部存储原子变量往期内容回顾std::unique_lock类模板
互斥锁保证了线程间的同步#xff0c;却将并行操作变成了串行操作#xff0c;对性能有较大影响#xff0c;所以我们要尽可能减小锁的区间粒度。 lock_guard只能保证在析构的时… 目录std::unique_lock类模板仅调用一次线程局部存储原子变量往期内容回顾 std::unique_lock类模板
互斥锁保证了线程间的同步却将并行操作变成了串行操作对性能有较大影响所以我们要尽可能减小锁的区间粒度。 lock_guard只能保证在析构的时候进行解锁操作所以其本身并没有提供加锁解锁的接口
class logFile{
private:std::mutex mtx;ofstream f;
public:logFile() {f.open(log.txt);}~logFile() {f.close();}void sharedPrint(string msg, int id) {{std::lock_guardstd::mutex guard(mtx);// do sth1}// do sth2// ...{std::lock_guardstd::mutex guard(mtx);// do sth3f msg id endl;cout msg id endl;}}
};上面代码中sharedPrint函数内部有两段代码需要进行加锁保护此时使用lock_guard就需要创建两个局部对象来管理同一个互斥锁。 其实可以使用unique_lock它提供了**lock()和unlock()**接口能记录现在处于上锁还是没上锁状态在析构的时候会根据当前状态来决定是否要进行解锁lock_guard就一定会解锁 void sharedPrint(string msg, int id) {std::unique_lockstd::mutex guard(mtx);// do sth1guard.unlock(); // 临时解锁// do sth2guard.lock(); // 继续上锁// do sth3f msg id endl;cout msg id endl;// guard.unlock(); // 这个可要可不要因为析构的时候也会自动执行的}仅调用一次
程序免不了要初始化数据线程并发没有某种同步手段来控制会导致初始化函数多次运行。
c11种提供仅调用一次的功能首先声明一个once_flag类型的变量作为初始化标志最好是静态、全局的这样对于线程就是可见的了。然后调用专门的call_once()函数以函数式编程的方式传递这个标志和初始化函数这样就可以保证即使多个线程重入call_once()也只能由一个线程会成功初始化
#include iostream
#include thread
#include mutex// 全局的初始化标志
static std::once_flag flag;
auto f []()
{std::call_once(flag,[](){std::cout only once std::endl;});
};
int main() {// 启动两个线程运行函数fstd::thread t1(f);std::thread t2(f);t1.join();t2.join();// std::cout finished std::endl;return 0;
}实际编译结果如下
only once线程局部存储
当读写全局变量时一般也会出现数据竞争但是全局变量不一定是必须共享的可能仅仅是为了方便线程传入传出数据不是共享所有权。此时可以使用关键字thread_local实现线程局部缓存被其标志的变量在每个线程里都会有一个独立的副本。
#include iostream
#include threadint main() {// 启动两个线程运行函数fthread_local int n 0;auto f [](int x){n x;std::cout n std::endl;};std::thread t1(f, 10);std::thread t2(f, 20);t1.join();t2.join();// std::cout finished std::endl;return 0;
}结果是
10
20说明两个线程互不干扰如果将变量声明改为static两个线程会共享这个变量导致连续加两次结果是下面
10 or 20
30 30原子变量
对于非独占、必须共享的数据要保证多线程读写共享数据一致就要解决同步问题两个线程得互斥。但是mutex互斥量成本较高可以使用atmoic原子化操作。
int main() {static std::atomic_flag flag {false}; // 原子化的标志量static atomic_int n; // 原子化的intauto f [](){auto value flag.test_and_set(); // TAS检查原子标志量if (value) {std::cout flag has been set std::endl;} else {std::cout set flag by std::this_thread::get_id() std::endl; // 输出线程id}n 100; // 原子变量加法运算std::this_thread::sleep_for(std::chrono::seconds(5)); //线程睡眠std::cout n std::endl;};std::thread t1(f);std::thread t2(f);t1.join();t2.join();
}往期内容回顾 C多线程快速入门一基本常用操作