网络应用随处可见。任什么时候候你浏览Web、发送邮件,你就在使用一个网络应用程序。有趣的是,全部网络应用都是基于相同的基本编程模型,有着类似的总体逻辑结构,而且依赖相同的编程接口。git
客户端和服务器一般运行在不一样的主机上,而且经过计算机网络的硬件和软件资源来通讯。
对于一个主机而言,网络只是又一种I/O设备,做为数据源和数据接收方。一个插到I/O总线扩展槽的适配器提供了到网络的物理接口。从网络上接收到的数据从适配器通过I/O和存储器总线拷贝到存储器,典型地是经过DMA传送。
web
listen函数将sockfd从一个主动套接字转化为一个监听套接字。该套接字能够接受来自客户端的链接请求。backlog参数暗示了内核在开始拒绝链接请求以前,该放入队列中等待的未完成链接请求的数量。数据库
Web客户端和服务器之间的交互用的是一个基于文本的应用级协议,叫作HTTP。HTTP是一个简单的协议。一个web客户端(即浏览器)打开一个到服务器的因特网链接。浏览器读取这些内容,并请求某些内容。服务器响应所请求的内容,而后关闭链接。浏览器读取并把它显示在屏幕内主要的区别是Web内容能够用HTML来编写。一个HTML程序(页)包含指令(标记)它们告诉浏览器如何显示这页中的各类文本和图形对象。编程
到目前为止,咱们主要将并发看作是一种操做系统内核用来运行多个应用程序的机制。可是,并发不只仅局限于内核。它也能够在应用程序中扮演重要角色。例如,咱们已经看到Unix信号处理程序如何容许应用响应异步事件,例如用户键入。或者程序访问虚拟存储器的个未定义的区域.应用级并发在其余状况下也是颇有用的。浏览器
在接受链接请求以后,服务器派生一个子进程,这个子进程得到服务器描述符表的完整拷贝。子进程关闭它的拷贝中的监听描述符3,而父进程关闭它的已链接描述符4的拷贝,由于再也不须要这些描述符了。这就获得了图中的状态,其中子进程正忙于为客户端提供服务。由于父子进程中的已链接描述符都指向同一个文件表表项,因此父进程关闭它的已链接描述符的拷贝是相当重要的。不然,将永远不会释放已链接描述符4的文件表条目,并且由此引发的存储器泄漏将最终消耗尽可用的存储器,使系统崩溃。如今假设在父进程为客户端1建立了子进程以后,它接受一个新的客户端2的链接请求,并返回一个新的已链接描述符(好比描述符5)如图所示。而后,父进程又派生另外一个子进程,这个子进程用已链接描述符5为它的客户端提供服务,如图所示。此时,父进程正在等待下一个链接请求,而两个子进程正在形地为它们各自的客户端提供服务。
安全
一个服务器,它有两个I/O事件:1)网络客户端发起链接请求,2)用户在键盘上键入命令行。咱们先等待那个事件呢?没有那个选择是理想的。若是accept中等待链接,那么没法相应输入命令。若是在read中等待一个输入命令,咱们就不能响应任何链接请求(这个前提是一个进程)。
针对这种困境的一个解决办法就是I/O多路复用技术。基本思想是:使用select函数,要求内核挂起进程,只有在一个或者多个I/O事件发生后,才将控制返给应用程序。如图所示:横向的方格能够看做是一个n位的描述符向量。如今,咱们定义第0位描述是“标准输入”,第3位描述符是“监听描述符”。服务器
每一个线程都有本身的线程上下文,包括一个线程ID、栈、栈指针、程序计数器、通用目的寄存器和条件码。全部的运行在一个进程里的线程共享该进程的整个虚拟地址空间。因为线程运行在单一进程中,所以共享这个进程虚拟地址空间的整个内容,包括它的代码、数据、堆、共享库和打开的文件。
1、线程执行模型网络
2、Posix线程多线程
Posix线程是C程序中处理线程的一个标准接口。并发
万能函数:
void func(void parameter)
typedef void (uf)(void para)
3、建立线程
1.建立线程:
pthread_create函数
#include <pthread.h>
typedef void (func)(void );int pthread_create(pthread_t tid, pthread_attr_t attr, func f, void arg);
功能:建立一个新的线程,带着一个输入变量arg,在新线程的上下文运行线程例程f。
2.查看线程ID
pthread_self函数
#include <pthread.h>
pthread_t pthread_self(void);
功能:返回调用者的线程ID(TID)
4、终止线程
1.终止线程的方式:隐式终止、显示终止
2.pthread_exit函数
#include <pthread.h>
void pthread_exit(void *thread_return);
3.pthread_cancle函数
#include <pthread.h>
void pthread_cancle(pthread_t tid);
5、回收已终止线程的资源
pthread_join函数:
#include <pthread.h>
int pthread_join(pthread_t tid,void **thrad_return);
6、分离线程
pthread_detach函数
#include <pthread.h>
void pthread_detach(pthread_t tid);
功能:分离可结合线程tid。
7、初始化线程
pthread_once函数
#include <pthread.h>
pthread_once_t once_control = PTHREAD_ONCE_INIT;int pthread_once(pthread_once_t once_control, void (init_routine)(void));
全局变量和static变量是存储在数据段,因此多线程共享之!因为线程的栈是独立的,全部线程中的自动变量是独立的。即便多个线程运行同一段代码总的自动变量,那么他们的值也是根据线程的不一样而不一样。
信号量一般称之为PV操做,虽然它的思想是将临界代码保护起来,达到互斥效果。这里面操做系统使用到了线程挂起。
将线程i的循环代码分解成五个部分:
到目前为止,在对并发的研究中,咱们都假设并发线程是在单处许多现代机器具备多核处理器。并发程序一般在这样的机器上运理器系统上执行的。然而,在多个核上并行地调度这些并发线程,而不是在单个核顺序地调度,在像繁忙的Web服务器、数据库服务器和大型科学计算代码这样的应用中利用这种并行性是相当重要的。
condvar.c
运行结果:
mutex
用于保护资源,wait
函数用于等待信号,signal
函数用于通知信号,wait
函数中有一次对`mutex的释放和从新获取操做,所以生产者和消费者并不会出现死锁。
share.c
运行结果:
得到线程的终止状态,thr_fn 1
,thr_fn 2
和thr_fn 3
三个函数对应终止线程的三种方法,即从线程函数return
,调用pthread_exit
终止本身和调用pthread_cancel
终止同一进程中的另外一个线程。
countwithmutex.c
运行结果:
引入互斥锁(Mutex),得到锁的线程能够完成”读-修改-写”的操做,而后释放锁给其它线程,没有得到锁的线程只能等待而不能访问共享数据。
semphore.c
运行结果:
semaphore
表示信号量,semaphore
变量的类型为sem_t,sem_init()
初始化一个semaphore
变量,value
参数表示可用资源 的数量,pshared
参数为0表示信号量用于同一进程的线程间同步。
count.c
运行结果:
这是一个不加锁的建立两个线程共享同一变量都实现加一操做的程序,在这个程序中虽然每一个线程都给count加了5000,但因为结果的互相覆盖,最终输出值不是10000,而是5000。
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 200/400 | 2/4 | 18/38 | |
第三周 | 100/500 | 1/5 | 10/48 | |
第四周 | 250/750 | 1/6 | 10/58 | |
第五周 | 100/850 | 1/7 | 10/68 | |
第六周 | 100/950 | 1/8 | 12/80 | |
第七周 | 200/1150 | 1/9 | 12/92 | |
第八周 | 124/1274 | 2/11 | 10/102 | |
第九周 | 205/1479 | 2/13 | 5/107 | |
第十周 | 333/1712 | 2/15 | 10/117 | |
第十一周 | 758/2470 | 3/18 | 12/129 | |
第十二周 | 25/2495 | 3/21 | 10/139 | |
第十三周 | 956/3451 | 1/22 | 10/149 |