C++并发与多线程(4)——unique_lock详解
一、unique_lock取代lock_guard unique_lock比lock_guard灵活很多(多出来很多用法),但是效率差一点,内存的占用也会大一点。 cppreference对此的描述是: A unique lock is an object that manages a mutex object with unique ownership in both states: locked and unlocked. On construction (or by move-assigning to it), the object acquires a mutex object, for whose locking and unlocking operations becomes responsible. The object supports both states: locked and unlocked. This class guarantees an unlocked status on destruction (even if not called expl...
C++并发与多线程(3)——互斥量与死锁
零、引子 1.创建多线程 在前几次学习中,我们都是创建一个子线程,其实多个子线程是比较常见的。一般在创建多个线程时,把thread对象放入到容器中管理,看起来像个thread对象的数组,对一次创建大量的线程并对大量线程进行管理有好处。下面是一个例子: 123456789101112131415161718192021222324252627#include <iostream>#include <thread>#include <vector>using namespace std;void get_id(int i){ cout << "第" << i << "线程id为" << this_thread::get_id() << "开始执行" << endl; cout << "第" << i << "线程id为" <&l...
C++并发与多线程(2)——线程传参问题
零、复习隐式转换和显式转换的概念 隐式转换(系统根据程序的需要而自动转换的): 123456789void fun(CTest test); class CTest { public: CTest(int m = 0); } fun(20);//隐式转换,这里的20生成了一个临时对象 显式转换(需要加括号标注想要转换的类型): 12345678910void fun(CTest test); //但有时隐式转换并不是我们想要的,可在构造函数前加上关键字explicit,来指定显式调用class CTest { public: explicit CTest(int m = 0); } fun(20);//错误,隐式转换fun(static_cast<CTest>(20)); //正确,显式转换,这里的20生成了一个临时对象 一、获得线程id 格式:std::thread::get_id cpp官网解释: Get thread id Returns the thread id. If the thread ...
C++并发与多线程(1)——创建线程
零、注意事项 程序运行起来,生成一个进程,该进程所属的主线程开始自动运行;当主线程从main()函数返回,则整个进程执行完毕。 主线程从main()开始执行,那么我们自己创建的线程,也需要从一个函数开始运行,一旦这个函数运行完毕,线程也结束运行。 整个进程是否执行完毕的标志是:主线程是否执行完,如果主线程执行完毕了,就代表整个进程执行完毕了,此时如果其他子线程还没有执行完,也会被强行终止(此条有例外,以后会解释)。 一、创建线程的一般方法 首先要引入头文件#include,C++11中管理线程的函数和类在该头文件中声明,其中包括std::thread类。 创建线程的格式是std::thread mythread(function);,意思是创建了一个名为mythread的线程,并且线程mythread开始执行。其中可调用对象名(即括号中的function)作为第一个参数,第二个参数为该函数的第一个参数,如果该函数接收多个参数就依次写在后面。此时线程开始执行。 需要注意,线程类参数是一个可调用对象,C++中的可调用对象可以是函数、函数指针、lambda表达式、bind创建的对象...
STM32学习笔记(2)——按键输入实验
前情提示: 我们之前简要做了LED和蜂鸣器的学习笔记。因此,本文程序涉及到LED和蜂鸣器的程序段不再重复出现。 零、按键基本认识 1、防抖 按键机械触点断开、闭合的时候,由于触点的弹性作用,按键开关不会马上稳定接通或一下子断开,而是会产生一些波纹信号,这些波纹信号会干扰高低电平的判断。如下图所示,在按键按下的前后均有信号抖动: 为了解决这个问题,有一些电路自带消抖功能,利用电容充放电的延时,消除了干扰波纹,从而简化了软件的处理,软件只需检测引脚的高低电平即可。这叫硬件消抖。 然而,我们的实验板却没有硬件消抖功能,因此,当用户按下按键时,软件需要延时一会儿(一般为10ms左右),待引脚的输入电平稳定后再判断高低电平。这叫软件消抖。 大致的思路如下: 123456789101112uint8_t KEY_Scan(void){ if(KEY按下) { delay_ms(10);//延时10-20ms,防抖。 if(KEY确实按下) { return KEY_Value; ...
STM32学习笔记(1)——LED和蜂鸣器
阅读前提示: 我们使用的板子是正点原子的ALIENTEK精英STM32F103。本文使用固件库进行编程,因为使用固件库编程较为方便,且阅读程序也较易理解。 零、GPIO简介及其库函数 1. GPIO简介 7组IO口(具体地址可见头文件stm32f10x.h): GPIOA ~ GPIOG。每组IO口可控制7个寄存器,这7个寄存器可控制一组GPIO的16个IO口: GPIOx_CRL:端口配置低寄存器 GPIOx_CRH:端口配置高寄存器 GPIOx_IDR:端口输入寄存器 GPIOx_ODR:端口输出寄存器 GPIOx_BSRR:端口位设置/清除寄存器 GPIOx_BRR:端口位清除寄存器 GPIOx_LCKR:端口配置锁存寄存器 16个管脚(GPIO_Pin)(位于头文件stm32f10x_gpio.h): GPIO_Pin_0 ~ GPIO_Pin_15,若想全部选中则GPIO_Pin_All。 4种输入模式(GPIO_Mode)(位于头文件stm32f10x_gpio.h): 浮空输入(GPIO_Mode_IN_FLOATING) 上拉输入(GPIO_Mode_IPU...
植物大战僵尸 PVZ Qt版
一、初步设计 1. 框架 本程序分为两个部分:菜单界面采用QWidget实现,有一个父窗口,通过信号槽机制调用各种子窗口;游戏界面使用QGraphicsScene框架实现,里面包含view和各种图形项item。 本程序采用面向对象程序设计思路,创建基类植物Plant、僵尸Zombie、卡牌Cards,在这基础上派生出不同的类,如豌豆射手、路障僵尸等。创建一个Map类,用以记录植物的位置,以及是否可以种植。 2. 界面 首先,整个窗口界面是900X600的大小,并且大小不可调。 菜单界面依然是植物大战僵尸的那个味道,放置熟悉的菜单背景,在右侧放置游戏开始按钮,玩家点击后程序会展示僵尸的一封信,再次点击即可进入游戏界面。 游戏界面也依然是植物大战僵尸的那个味道,几乎差不多。最上方是卡牌选择框,在选择框左侧显示阳光点数。左上角是返回菜单和游戏暂停按钮,在左侧摆放割草机,右侧出僵尸,正中一大片区域放植物,最下方展示游戏目标。 游戏开始,依然是植物大战僵尸的味道。玩家选择卡牌,在地图中央点击放置植物;若想铲除植物,则需点击右上方的铲子进行铲除操作。 3. 图形项Item 基于QGraphi...
C++学习笔记(7)——标准模板库STL之set和map
零、pair类模板 pair与python中字典的键值对非常像。在C++中,pair的定义是: 12345template <typename T1, typename T2>struct pair{ T1 first; T2 second; ...下面都是各种构造函数重载版本,不写了 可以不写参数:pair<string, double> p 可以写参数(常用):pair<string, double> p1("xiaoming", 78) 可以这样初始化:pair<string, double> p2(pair<string, double>("xiaoming", 78)),当这样写的时候,其实是用了定义中的函数模板,参数必须是pair模板类对象的引用。 也可以这样初始化:pair<string, double> p3 = make_pair("xiaoming", 78) 访问pair对象的“键”(Key):p.first 访问pa...
C++学习笔记(6)——标准模板库STL之vector和list
一、动态数组vector 1.初始化 初始化为空:vector<int> v; 用另一个vector来初始化,即构造一个副本:vector<int> v(v1); 大小为n,并全部初始化为元素i :vector<int> v(n, i); 构造大小为n的容器,没有初始化里面的元素:vector<int> (n); 构造大小为4,并初始化里面的各个元素:vector<int> {1,2,3,4}; 数组a[0]到a[5]的内容放进v:vector<int> v(a, a+5); 2.元素个数 v.size(); //返回容器中元素的个数,返回类型是int v.capacity(); //返回容器中的容量,容器的预留空间也会计算在内 3.添加/插入元素 v.push_back(n); //将n加到容器末尾 v.insert(i, n); //将n插入到迭代器i指向的位置,并返回i v.insert(i, i_first, i_end); //将其他容器上的区间[i_first,i_end)中的元素插入到迭代器i指...
C语言中的函数指针
直接上程序说明函数指针是怎么写的: 1234567891011121314151617181920212223242526272829#include <iostream>using namespace std;int power(int a){ return a*a;}int cube(int a){ return a*a*a;}void aPrint(int a){ cout<<"test:"<<a<<endl;}int main(){ int (*p)(int); void (*print)(int); p = power; print = aPrint; print((*p)(6)); p = cube; print((*p)(6)); return 0;} 输出: 12test:36test:216



