C++11:多线程(1)

2023-03-10 13:26:30 浏览数 (1)

前言

代码语言:javascript复制
之前的工作项目基本不使用多线程,一直对多线程的理解比较浅显,一般应用也是主从两个线程,也不涉及资源锁,以及其他的各种锁,信号量之类的,更别提线程池之类的,这次也特意学习记录一下多线程。

库知识

C 11现在也有了自己的多线程库,从C 11的线程库开始学习了解。 库主要分为:

代码语言:javascript复制
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <future>

std::thread

std::thread类,主要用来创建创建线程,对线程对象进行相关操作,控制线程的生命周期。 std::thread 类成员函数主要如下:

代码语言:javascript复制
//构造函数
thread() noexcept = default;
thread(thread&) = delete;
thread(const thread&) = delete;
thread(const thread&&) = delete;
thread(thread&& __t) noexcept     { swap(__t); }
//析构函数
  ~thread()
   {
     if (joinable())
std::terminate();
   }
//交换函数,用来交换底层句柄
void    swap(thread& __t) noexcept    { std::swap(_M_id, __t._M_id); }
//join状态函数,判断线程是否能被线程控制
bool  joinable() const noexcept   { return !(_M_id == id()); }  、
//join 等待线程执行结束
void join();
//线程分离函数
void detach();
//得到线程ID
thread::id get_id() const noexcept { return _M_id; }
//native_handle_type 得到与操作系统相关的原生线程句柄
 typedef __gthread_t			native_handle_type;
 native_handle_type native_handle() { return _M_id.M_thread; }
 //hardware_concurrency 获得当前程序最大支持的线程数,多线程一般代表系统核数
 static unsigned int hardware_concurrency() noexcept;

std::mutex

互斥锁,主要用来线程同步,保证在同一时间内只有一个线程对某一资源进行读写操作。 std::mutex 类主要有以下几种类,mutex,recursive_mutex,timed_mutex,recursive_timed_mutex几种类。

mutex

基础类:

代码语言:javascript复制
//加锁
void lock();
//解锁
void unlock();
//尝试锁
bool try_lock();

recursive_mutex

递归锁:允许在同一个线程内,多一个互斥量进行多次请求。即在同一个线程内,多次获取锁定同一个递归锁,且不会产生死锁。

代码语言:javascript复制
//构造函数
recursive_mutex() = default;
recursive_mutex(const recursive_mutex&) = delete;
//析构函数
~recursive_mutex() = default;
//加锁
void lock();
//解锁
void unlock();
//尝试锁
bool try_lock();

timed_mutex

定时锁:

代码语言:javascript复制
//构造函数
timed_mutex() = default;
timed_mutex(const timed_mutex&) = delete;
//析构函数
~timed_mutex() = default;
//加锁
void lock();
//解锁
void unlock();
//尝试锁
bool try_lock();
//等待锁,在调用时,在一个时间段内,如果锁被释放,加锁,否则,返回false。
template <class _Rep, class _Period>
bool try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) { return _M_try_lock_for(__rtime); }
//等待锁,在某个时刻到达之前,如果锁被释放,加锁,否则,返回false
template <class _Clock, class _Duration>
bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) { return _M_try_lock_until(__atime); }

recursive_timed_mutex

递归定时锁:具备递归锁和定时锁的所有特性。

代码语言:javascript复制
//构造函数
recursive_timed_mutex() = default;
recursive_timed_mutex(const recursive_timed_mutex&) = delete;
//析构函数
~recursive_timed_mutex() = default;
//加锁
void lock();
//解锁
void unlock();
//尝试锁
bool try_lock();
//等待锁,在调用时,在一个时间段内,如果锁被释放,加锁,否则,返回false。
template <class _Rep, class _Period>
bool try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) { return _M_try_lock_for(__rtime); }
//等待锁,在某个时刻到达之前,如果锁被释放,加锁,否则,返回false
template <class _Clock, class _Duration>
bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) { return _M_try_lock_until(__atime); }

lock_guard

代码语言:javascript复制
//构造函数
 explicit lock_guard(mutex_type& __m) : _M_device(__m)   { _M_device.lock(); }
 lock_guard(mutex_type& __m, adopt_lock_t) noexcept : _M_device(__m)   { } // calling thread owns mutex
lock_guard(const lock_guard&) = delete;
 //析构函数
  ~lock_guard()   { _M_device.unlock(); }

个人理解:类似于智能指针,在生命周期结束时,析构,能够自动解锁,不需要手动解锁,提供了一定的安全性。

unique_lock

代码语言:javascript复制
//构造函数
unique_lock() noexcept  : _M_device(0), _M_owns(false)  { }
//构造函数,只允许显示调用
explicit unique_lock(mutex_type& __m) : _M_device(std::__addressof(__m)), _M_owns(false) { 	lock(); 	_M_owns = true;  }
//构造函数,无互斥所有权
unique_lock(mutex_type& __m, defer_lock_t) noexcept: _M_device(std::__addressof(__m)), _owns(false){ }
//构造函数,尝试获得锁的所有权,而不阻塞
 unique_lock(mutex_type& __m, try_to_lock_t)  : _M_device(std::__addressof(__m)), M_owns(_M_device->try_lock()) { }
//构造函数,拥有互斥锁所有权
unique_lock(mutex_type& __m, adopt_lock_t) noexcept : _M_device(std::__addressof(__m)), M_owns(true){
// XXX calling thread owns mutex
}
//析构函数
~unique_lock() { if (_M_owns) unlock();}
//锁
void lock();
//尝试锁
bool try_lock();
//等待
bool try_lock_until();
bool try_lock_for();
//解锁
void unlock();
//交换所有权
void swap(unique_lock& __u);
//释放
 mutex_type* release();
 //返回锁状态
  bool  owns_lock();
  //获取锁
 mutex_type* mutex() const noexcept { return _M_device; }

个人理解:对锁对象的控制权,百度来的,通用互斥包装器,允许“延迟锁定,锁定的有限尝试、递归锁定、所有权转移和条件变量一同使用”,unique_lock 比 lock_guard 使用更加灵活,功能更加强大。但是使用unique_lock 需要付出更多的时间成本、性能成本。

std::condition_variable

std::condition_variable 条件变量,性能消耗小于std::mutex,对于线程同步,效率高于 std::mutex。std::conditon_variable 有两个接口 wait(),可以是线程处与休眠状态,另一个就是notify_one(),唤醒处于wait中的其中一个条件变量,(可能当时有很多条件变量处于wait状态)。notify_all(),唤醒所有处于wait状态的条件。

代码语言:javascript复制
//构造函数
condition_variable() noexcept;
condition_variable(const condition_variable&) = delete;
//析构函数
~condition_variable() noexcept;
//唤醒单个线程
void notify_one() noexcept;
//唤醒所有线程
void notify_all() noexcept;
//休眠函数
void wait(unique_lock<mutex>& __lock) noexcept;
void wait(unique_lock<mutex>& __lock, _Predicate __p) { while (!__p()) wait(__lock);}
//休眠函数,等待时间点,线程收到通知或者指定时间点abs_time超时之前,线程都会处于阻塞状态,超时或者被唤醒,返回
cv_status wait_until(unique_lock<mutex>& __lock, const chrono::time_point<__clock_t, _Duration>& __atime) { return __wait_until_impl(__lock, __atime); }
cv_status wait_until(unique_lock<mutex>& __lock,const chrono::time_point<_Clock, _Duration>& __atime)
{
	// DR 887 - Sync unknown clock to known clock.
	const typename _Clock::time_point __c_entry = _Clock::now();
	const __clock_t::time_point __s_entry = __clock_t::now();
	const auto __delta = __atime - __c_entry;
	const auto __s_atime = __s_entry   __delta;
	return __wait_until_impl(__lock, __s_atime);
} 
bool wait_until(unique_lock<mutex>& __lock,const chrono::time_point<_Clock, _Duration>& __atime,
_Predicate __p) { 	while (!__p()) 	if (wait_until(__lock, __atime) == cv_status::timeout) 	return __p(); 	
return true;}
//线程休眠,加了时间限制,在超时之前,处于休眠状态,如果超时或者被唤醒,wait_for 返回
cv_status wait_for(unique_lock<mutex>& __lock,  const chrono::duration<_Rep, _Period>& __rtime)
{ return wait_until(__lock, __clock_t::now()   __rtime); }
bool wait_for(unique_lock<mutex>& __lock,  const chrono::duration<_Rep, _Period>& __rtime,
  _Predicate __p){ return wait_until(__lock, __clock_t::now()   __rtime, std::move(__p)); }

0 人点赞