去图书馆借了本书,一直不知道在瞎忙什么一直没看。终于放假了,便开始学习。
并发:
就是两个或者更多独立的活动同时发生。而计算机里面的并发是指在单个操作系统里同时执行多个独立的活动,而不是按照顺序地一个接着一个。
在多任务的服务器已经通过切换任务允许在一台计算机在同一时间运行多个应用程序。
硬件并发:
多核心的计算机(拥有多个处理器或者多核处理器或者两者兼具),这些计算机都能并行运行超过一个任务。我们称为硬件并发。
一个双核计算机在处理两个任务时,每个任务可以在各自的核心进行执行。然而在单核机器上做任务切换时,每个任务的块都交替进行。
为了完成交替进行,该系统每次需要从一个任务切换到另一个时都得执行一次上下文切换,而这个是需要时间的。为了执行上下文切换,操作系统必须
为当前运行的任务保存cpu的状态和指令指针,算出要切换到哪个任务,并为要切换到的任务重新加载处理器状态。然后cpu可能要将新的任务的指令和
数据内存载入到缓存中,这可能会阻止cpu执行任何指令,造成进一步的延迟。
需要考虑的因素:
硬件线程的数量,硬件可真正并发执行多少独立的任务。超过硬件可并行运行的任务要执行,任务切换将被使用。
进程:
在多道程序环境下,程序的执行属于并发执行。为了能够使程序并发执行,并且可以对并发执行的程序加以控制和描述。
并发的途径:
多个单进程的线程
单一进程有里有多个线程
多个单进程的进程间的通信方式:
信号,套接字,文件,管道
单一进程里面有多个线程,这些线程都共享进程的地址空间,并且从所有线程中能够访问到大部分数据。但是确保每个线程访问数据的一致性是个问题。
但是单一进程中的多线程开销更小。
使用并发的原因:
分离和性能
为了性能而使用并发的两种方式:
任务并发和数据并发
任务并发:将单一的任务分成几部分各自并行运行,从而降低运行总时间(一个线程在执行算法的一部分拧一个线程在执行算法的另一部分)。
数据并发:每个线程在不同的数据部分上执行相同的操作。
什么时候不适用并行:
收益比不上成本的时候,性能不如预期的那么大。在启动线程时存在固有的开销,因为操作系统必须要为分配相关的内核资源和堆栈空间,然后
将新线程加入调度器中,所有这一切都需要占用时间。如果线程上的任务完成的快,这一切就微不足道。
线程的资源是有限的,如果太多线程同时运行,则会消耗操作系统资源,使得操作系统整体运行的更慢。
初入并发世界
#include <iostream>
using namespace std;
int main()
{
cout << "Hello World" << endl;
system("pause");
}
这个是单线程中运行的Hello World
下面是一个多线程的程序:
#include <iostream>
#include <thread>
using namespace std;
void hello()
{
cout << "Hello Concurrent World" << endl;
}
int main()
{
thread t(hello);
t.join();
system("pause");
}
两个程序的区别在于:
增加了#include <thread> 这是对多线程支持的头文件,用于管理线程的函数和类的声明。
增加了一个hello函数,这是因为每个线程都必须的有一个初始函数,新线程在这里开始执行。
对于应用程序来说,初始线程时main(),但其他线程需要通过thread对象的构造函数来指定,上面用t 的thread对象拥有新函数hello()作为初始函数。
与直接标准输出或是从main()调用hello()不同,该程序启动了一个新的线程,将线程数量一分为二,初始线程始于main()而新的线程始于hello()。
在新的线程启动之后,初始程序继续执行。如果它不等待新的线程结束,它将运行到main()结束,然后结束程序,从而造成有可能发生在新的线程有机会运行之前,所以调用了join(),它的作用是调用线程(main()中)等待与thread相关联的线程。