C++11 常用知识点汇总

C++11 新增的知识点整理总结

一:关键词和语法

auto:可以根据右值,推到出右值的类型,然后左边变量的类型也就已知了

nullptr: 给指针专用(能够区分整数进行区别) #define NULL 0

for(Type val : container) { }   遍历容器元素

右值引用:move 移动语义函数和forward类型完美转发函数

模板的一个新特性:typename... A 表示可变参(类型参数)

 二、绑定器和函数对象

function :函数对象

bind:绑定器

bind1st 和 bind2nd + 二元函数对象 = 一元函数对象

lambda表达式

三、智能指针

shared_ptr  和 weak_ptr

四、容器

unordered_set  和 unordered_map : 哈希表

array:数组                          

forward_list : 向前链表(轻量的list)

五:C++语言级别支持的多线程

1.通过thread类编写C++多线程程序 可以跨平台

thread/   mutex/   condition_variable

lock_quard  /  unique_lock

atomic 原子类型基于 CAS操作的原子类型,线程安全

sleep_for

相当于C++语言封装了一层api调用 了底层的线程库 

 线程内容:

1.怎么创建启动一个线程

        std::thread定义一个线程对象,传入线程所需要的线程函数和参数,线程自动开启

2.子线程如何结束:

        子线程运行完成,线程就结束

3.主线程如何处理子线程:

        join() ;   //等待相应子线程结束,主线程才执行下一步

        detach();  //把相应线程设置为分离线程,主线程结束,整个进程结束,所有子线程自动结束

void threadHandler1(int time)
{
    std::this_thread::sleep_for(std::chrono::seconds(time));
    std::cout << "hello thread! 1" << std::endl;
}

int main()
{
    //定义了一个线程对象,传入一个线程函数
    std::thread t1(threadHandler1,2);
    //主线程运行完成,查看如果当前进程还有未完成的子线程,进程就会异常终止
    // t1.join(); //等待子线程结束,主线程继续往下继续
    t1.detach(); //分离子线程
    std::cout<< "main thread done! " << std::endl;


    return 0;
}

2.线程间互斥-mutex互斥锁和lock_guard

竞态条件:多线程程序执行的结果是一致的,不会随着cpu对线程不同的调用顺序,而产生不同的运行结果。

例子:会出现相同的结果

//模拟三个车站买票的窗口的程序
int ticketCount = 100;

void sellTicket(int index)
{
    while (ticketCount > 0)
    {
        std::cout <<  ticketCount  <<std::endl;
        ticketCount --;
        std::this_thread::sleep_for(std::chrono::seconds(2));
    }
}


int main()
{
    std::list<std::thread> tlist;
    for(int i = 1; i < 4; ++ i)
    {
        tlist.push_back(std::thread(sellTicket,i));
    }
    for(std::thread &t: tlist)
    {
        t.join();
    }
    std::cout << "票还剩余:" << ticketCount << "张!" <<std::endl;

    return 0;
}

#include <mutex>  

1.这个锁修改的有问题:比如在ticketCount 这个代码区域有return 或者break的话,锁就不会被释放掉了。后边的子线程就再也拿不到锁了

//模拟三个车站买票的窗口的程序
int ticketCount = 100;
std::mutex mtx;//全局的一把互斥锁

void sellTicket(int index)
{
    while (ticketCount > 0)
    {
        mtx.lock();
        if(ticketCount > 0)
        {
            std::cout <<  ticketCount  <<std::endl;
            ticketCount--;
            
        }
        mtx.unlock();
        // std::this_thread::sleep_for(std::chrono::seconds(2));
    }
}


int main()
{
    std::list<std::thread> tlist;
    for(int i = 1; i < 4; ++ i)
    {
        tlist.push_back(std::thread(sellTicket,i));
    }
    for(std::thread &t: tlist)
    {
        t.join();
    }
    std::cout << "票还剩余:" << ticketCount << "张!" <<std::endl;

    return 0;
}

lock_guard:智能锁,不能做拷贝构造和赋值

int ticketCount = 100;
std::mutex mtx;//全局的一把互斥锁

void sellTicket(int index)
{
    while (ticketCount > 0)
    {
        //类似智能指针scoped_ptr,拷贝构造delete,出了作用域自动解锁
        std::lock_guard<std::mutex> lock(mtx); 
        if(ticketCount > 0)
        {
            std::cout <<  ticketCount  <<std::endl;
            ticketCount--;
            
        }

    }
}

3.线程间同步通讯-生产者消费者模型 

多线程编程的两个问题:

1.线程间的互斥

        竞态条件: 临界区代码段,保证原子操作,用互斥锁mutex或者用轻量级的无锁实现CAS

2.线程间的同步通信

例子:生产者生产一个物品,通知消费者消费一个,消费完了消费者再通知生产者继续生产物品

#include <mutex>
#include <queue>
#include <condition_variable>

//定义互斥锁
std::mutex mtx; 
//定义条件变量,做线程间的通信
std::condition_variable cv; 

class Queue{
    public:
        void put(int val)
        {
            std::unique_lock<std::mutex> lck(mtx);
            while (!que.empty())
            {
                //que不为空,生产者应该通知消费者去消费,消费完了,再继续生产
                //生产者线程应该进入阻塞状态,并且把mtx互斥释放掉
                cv.wait(lck); //需要的是unique_lock
            }
            que.push(val);
            /*
            notify_one(); 通知一个线程
            notify_alll(); 通知所有线程
            */
            cv.notify_all(); 
            std::cout << "生产者 生产:" << val << "号物品" << std::endl;
        }
        int get()
        {
            std::unique_lock<std::mutex> lck(mtx);
            while (que.empty())
            {
                cv.wait(lck);
            }
            int val = que.front();
            que.pop();
            cv.notify_all();
            std::cout << "消费者 消费:" << val << "号物品" << std::endl;
            return val;
        }
    private:
        std::queue<int> que;
};

void producer(Queue *que)
{
    for(int i = 1; i <= 10; ++i)
    {
        que->put(i);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

void consumer(Queue *que)
{
    for(int i = 1; i <= 10; ++i)
    {
        que->get();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

int main()
{
    Queue que;

    std::thread t1(producer,&que);
    std::thread t2(consumer,&que);
    t1.join();
    t2.join();
    return 0;
}

4.lock_guard 和 unique_lock 详解

unique_lock     condition_variable

1.lock_guard  和   unique_lock

2.condition_variable    wait 和notify_all 方法

lock_guard源码:

可以看出不能用在函数参数传递或者返回过程中,因为会用到赋值或者拷贝。只能用在简单的临界区代码段的互斥操作中

template<typename _Mutex>
class lock_guard
{
public:
    typedef _Mutex mutex_type;

    //在构造函数做了mutex锁的调用获取锁lock()
    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

    //在析构函数做了mutex锁的调用释放锁unlock()
    ~lock_guard()
    { _M_device.unlock(); }

    //不能做拷贝构造和赋值重载
    lock_guard(const lock_guard&) = delete;
    lock_guard& operator=(const lock_guard&) = delete;

private:
    mutex_type&  _M_device;
};

 unique_lock源码:

左值拷贝和赋值重载函数也被删除掉了,但是实现了右值拷贝和右值赋值重载函数。可以看出它不仅仅可以使用在简单的临界区代码段中的互斥操作,还能在函数调用过程中。

template<typename _Mutex>
    class unique_lock
    {
    public:
      typedef _Mutex mutex_type;

      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)), _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
      }

      template<typename _Clock, typename _Duration>
	unique_lock(mutex_type& __m,
		    const chrono::time_point<_Clock, _Duration>& __atime)
	: _M_device(std::__addressof(__m)),
	  _M_owns(_M_device->try_lock_until(__atime))
	{ }

      template<typename _Rep, typename _Period>
	unique_lock(mutex_type& __m,
		    const chrono::duration<_Rep, _Period>& __rtime)
	: _M_device(std::__addressof(__m)),
	  _M_owns(_M_device->try_lock_for(__rtime))
	{ }

      ~unique_lock()
      {
	if (_M_owns)
	  unlock();
      }

      unique_lock(const unique_lock&) = delete;
      unique_lock& operator=(const unique_lock&) = delete;

      unique_lock(unique_lock&& __u) noexcept
      : _M_device(__u._M_device), _M_owns(__u._M_owns)
      {
	__u._M_device = 0;
	__u._M_owns = false;
      }

      unique_lock& operator=(unique_lock&& __u) noexcept
      {
	if(_M_owns)
	  unlock();

	unique_lock(std::move(__u)).swap(*this);

	__u._M_device = 0;
	__u._M_owns = false;

	return *this;
      }

      void
      lock()
      {
	if (!_M_device)
	  __throw_system_error(int(errc::operation_not_permitted));
	else if (_M_owns)
	  __throw_system_error(int(errc::resource_deadlock_would_occur));
	else
	  {
	    _M_device->lock();
	    _M_owns = true;
	  }
      }

      bool
      try_lock()
      {
	if (!_M_device)
	  __throw_system_error(int(errc::operation_not_permitted));
	else if (_M_owns)
	  __throw_system_error(int(errc::resource_deadlock_would_occur));
	else
	  {
	    _M_owns = _M_device->try_lock();
	    return _M_owns;
	  }
      }

      template<typename _Clock, typename _Duration>
	bool
	try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
	{
	  if (!_M_device)
	    __throw_system_error(int(errc::operation_not_permitted));
	  else if (_M_owns)
	    __throw_system_error(int(errc::resource_deadlock_would_occur));
	  else
	    {
	      _M_owns = _M_device->try_lock_until(__atime);
	      return _M_owns;
	    }
	}

      template<typename _Rep, typename _Period>
	bool
	try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
	{
	  if (!_M_device)
	    __throw_system_error(int(errc::operation_not_permitted));
	  else if (_M_owns)
	    __throw_system_error(int(errc::resource_deadlock_would_occur));
	  else
	    {
	      _M_owns = _M_device->try_lock_for(__rtime);
	      return _M_owns;
	    }
	 }

      void
      unlock()
      {
	if (!_M_owns)
	  __throw_system_error(int(errc::operation_not_permitted));
	else if (_M_device)
	  {
	    _M_device->unlock();
	    _M_owns = false;
	  }
      }

      void
      swap(unique_lock& __u) noexcept
      {
	std::swap(_M_device, __u._M_device);
	std::swap(_M_owns, __u._M_owns);
      }

      mutex_type*
      release() noexcept
      {
	mutex_type* __ret = _M_device;
	_M_device = 0;
	_M_owns = false;
	return __ret;
      }

      bool
      owns_lock() const noexcept
      { return _M_owns; }

      explicit operator bool() const noexcept
      { return owns_lock(); }

      mutex_type*
      mutex() const noexcept
      { return _M_device; }

    private:
      mutex_type*	_M_device;
      bool		_M_owns;
    };

  /// Swap overload for unique_lock objects.
  /// @relates unique_lock
  template<typename _Mutex>
    inline void
    swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept
    { __x.swap(__y); }

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

std::condition_variable cv;
        1.使线程进入等待状态

        2.释放掉锁

        3.阻塞等待通知(notify_one() 或者 notify_all() )

std::unique_lock<std::mutex> l(mtx);

cv.wait(l);

cv.notify_all();

通知在cv上等待的线程(有cv.wait() 的),条件成立了。可以继续执行了

其他在cv上等待的线程,收到通知,从等待状态变为阻塞状态,然后获取到互斥锁了,就继续往下执行

5.基于CAS操作的atomic原子类型

#include <atomic>   //包含了很多原子类型

系统理论:CAS来保证上面++ -- 操作的原子特性就足够了,无锁操作

#include <iostream>
#include <atomic>
#include <thread>
#include <list>
//volatile  防止多线程对共享内存做缓存
volatile std::atomic_bool isReady = false;
volatile std::atomic_int  mycount = 0;

void task()
{
    while(!isReady)
    {
        std::this_thread::yield();//线程出让当前的CPU时间片,等待下一次的调用
    }
    
    for(int i = 0; i < 100; ++i)
    {
        mycount++;
    }
}


int main()
{

    std::list<std::thread> tlist;
    for(int i = 0; i < 10; ++ i)
    {
        tlist.push_back(std::thread(task));
    }
    std::this_thread::sleep_for(std::chrono::seconds(3));
    isReady = true;
    for(std::thread &t : tlist)
    {
        t.join();
    }
    
    std::cout << "mycount:" << mycount << std::endl;
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CID( ͡ _ ͡°)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值