0%

编译过程分为四个过程:预处理、编译、汇编、链接。

预处理:处理以 # 开头的指令;

编译:将源码 .cpp 文件翻译成 .s 汇编代码;

汇编:将汇编代码 .s 翻译成机器指令 .o 文件;

链接:汇编程序生成的目标文件,即 .o 文件,并不会立即执行,因为可能会出现.cpp 文件中的函数引用了另一个.cpp 文件中定义的符号或者调用了某个库文件中的函数。那链接的目的就是将这些文件对应的目标文件连接成一个整体,从而生成可执行的程序 .exe 文件。

20220214141659

链接分为两种:

静态链接:代码从其所在的静态链接库中拷贝到最终的可执行程序中,在该程序被执行时,这些代码会被装入到该进程的虚拟地址空间中。

动态链接:代码被放到动态链接库或共享对象的某个目标文件中,链接程序只是在最终的可执行程序中记录了共享对象的名字等一些信息。在程序执行时,动态链接库的全部内容会被映射到运行时相应进行的虚拟地址的空间。

二者的优缺点:

静态链接:浪费空间,每个可执行程序都会有目标文件的一个副本,这样如果目标文件进行了更新操作,就需要重新进行编译链接生成可执行程序(更新困难);优点就是执行的时候运行速度快,因为可执行程序具备了程序运行的所有内容。

动态链接:节省内存、更新方便,但是动态链接是在程序运行时,每次执行都需要链接,相比静态链接会有一定的性能损失。

效果比较好的数据有:

数据编号 备注
20211213_214603
20211213_210547
20211213_204805
20220103_195518 中间停了10s
20220103_200136 中间10s
20220103_201517 后半段人走开
20220103_202140 耳机架在桌子上,后半段走开了30-40s,再回来
20220103_204606 50多秒时人走开
20220103_205434 一直呼吸
20220103_205952 一直呼吸
20220103_210435 后面半段人走开
20220103_211403 中间人走开
20220103_212938 中间人走开
20220104_090548 一直呼吸
20220104_091117 中间人走开

实验分析

  • 耳机戴在头上得到的结果要比放在桌子上的结果好。
    分析:可能是由于人呼吸和心跳带动身体微小的动作会传递到头部,这样就会影响发射端,所以实验得到的波形可能不仅仅提取自反射信号,直达信号的变化很可能对实验结果有很大的影响。这也是该系统跟其它同类型的系统之间的一个区别,因为其它已有的测呼吸的工作大多是把发射端和接收端都放在人旁边,这样就只能从反射信号中提取信息,而我们的系统发射端是穿戴在任身体上的,呼吸和心跳的pattern会直接作用于发射端并通过直达信号反应出来。

后续的实验方向

  1. 结合直达信号和反射信号共同用于波形提取。可以考虑把直达信号左右一部分的路径和其它路径设置不同的权重再放到一起做pca。

  2. 参数的调整。呼吸和心跳的snr阈值可能还需要进一步调整,用于识别出没有呼吸和心跳的场景。

  3. 路径选择的方法可能还需要调试,目前的结果是百分比法(前10%)效果比阈值法要好一些。

  4. cir的长度和频率(现在是10)可能考虑一下是否需要调整。

死锁

如果一个进程集合中的每个进程都在等待只能由该进程集合中的其他进程才能引发的事件,那么该进程集合就是死锁的。

死锁的条件(四个同时满足)

  1. 互斥:每个资源要么已经分配给一个进程,要么就是可用的;

  2. 占有和等待:进程因请求资源而阻塞时,对已获得的资源保持不放;

  3. 不可抢占:已经分配的资源不能强制被抢占,只能进程自己释放;

  4. 环路等待:存在一种进程资源的循环等待链。

死锁的处理策略

  1. 死锁预防:破坏死锁的四个条件之一

    破环互斥条件:允许资源共享;

    破环占有和等待条件:一次性分配所有资源,只要缺少一个资源,其它资源也都不给他分配;

    破坏不可抢占:请求新资源得不到时,释放已经保持占有的资源,待以后重新申请;

    破坏环路等待:采用顺序资源分配法,给每个资源编号,进程申请资源的时候按照编号顺序申请,释放的时候则相反;

  2. 死锁避免:死锁避免事先预防策略,但是是采用资源动态分配的过程中,防止系统进入不安全状态,以避免死锁。

    预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得 较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全的状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。

    银行家算法:首先需要定义状态和安全状态的概念。系统的状态是当前给进程分配的资源情况。因此,状态包含两个向量Resource(系统中每种资源的总量)和Available(未分配给进程的每种资源的总量)及两个矩阵Claim(表示进程对资源的需求)和Allocation(表示当前分配给进程的资源)。安全状态是指至少有一个资源分配序列不会导致死锁。当进程请求一组资源时,假设同意该请求,从而改变了系统的状态,然后确定其结果是否还处于安全状态。如果是,同意这个请求;如果不是,阻塞该进程知道同意该请求后系统状态仍然是安全的。

  3. 死锁检测与解除:

    检测死锁:利用死锁原理化简资源分配图检测死锁的存在

    死锁解除:资源剥夺、撤销进程、进程回退

     剥夺资源:从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;
    
     撤消进程:可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止;所谓代价是指优先级、运行代价、进程的重要性和价值等。
    

智能指针

因为c++没有自动的内存回收机制,所以程序员每次在new一个对象的时候都需要手动delete,但是有的时候会忘记delete,或者因为程序分支等原因delete没有执行,就会使得对象没有释放而导致内存泄漏。

智能指针(shared_ptr)是一个类,存储了指向一个对象的指针,通过引用计数的方式记录有多少个智能指针对象共享同一个指针,它在指针没有被使用时会自动释放其内存。

引用计数

每次创建智能指针对象时,初始化其指针,引用计数设为1;

当智能指针对象成为另一个智能指针对象的副本时,执行拷贝构造函数,并将引用计数加1;

当执行赋值语句时,左操作数的引用计数减1,右操作数的引用计数加1;

当执行析构函数时,引用计数减1;

当引用计数为0时,释放内部指针指向的对象的空间。

循环引用

智能指针存在的一个经典问题就是循环引用问题,如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<iostream>
#include<memory>
using namespace std;
template<class T>
struct Node
{
Node(T data = T()) :_data(data), Pnext(NULL), Ppre(NULL)
{
}
~Node()
{
cout << "Call ~Node()" << endl;
}
shared_ptr<Node> Pnext;
shared_ptr<Node> Ppre;
T _data;
};

void testShared_Ptr()
{
shared_ptr<Node<int>>sp1(new Node<int>(1));
shared_ptr<Node<int>>sp2(new Node<int>(2));
cout << sp1.use_count() << endl;//1
cout << sp2.use_count() << endl;//1
sp1->Pnext = sp2;
sp2->Ppre = sp1;
cout << sp1.use_count() << endl;//2
cout << sp2.use_count() << endl;//2

/*Node<int> *a = new Node<int>(3);
delete a;
shared_ptr<Node<int>> c(new Node<int>(4));*/

}
int main()
{
testShared_Ptr();
cout<<"testShared_pte()函数运行结束"<<endl;
system("pause");
return 0;
}

在函数testShared_Ptr执行完之后,会先释放sp2,所以sp2的引用计数减1变为1,然后释放sp1的内存,sp1的引用计数也减1变为1。因为sp1中有对sp2的指针,sp2中也有sp1的指针,所以导致二者的引用计数都没有办法变为0,于是导致二者的内存空间都不会释放。

用CIR虚部做PCA效果更好

呼吸:

20211221145747

心跳:

20211221150024

实部和虚部分别独立做PCA再将结果相减:(效果又好了一点)

20211221190046

数据编号:20211213_214603