20145314郑凯杰《信息安全系统设计基础》第13周学习总结

20145314郑凯杰《信息安全系统设计基础》第13周学习总结

明确教材学习目标

学习目标

  • 掌握三种并发的方式:进程、线程、I/O多路复用
  • 掌握线程控制及相关系统调用
  • 掌握线程同步互斥及相关系统调用

教材学习内容总结

网络编程

  • 客户端-服务器编程模型

    1. 每个网络应用都是基于客户端-服务器模型。
    2. 一个应用是由一个服务器进程和一个或者多个客户端进程组成。
    3. 服务器管理某种资源,并通过操作资源来为客户端提供某种服务。
    4. 基本操作是事务。
  • 四个步骤

    1. 当客户端需要服务时,向服务器发送请求,发起一个事务。
    2. 服务器收到请求后,解释它,并以适当的方式操作它的资源。
    3. 服务器给客户端发送一个响应,并等待下一个请求。
    4. 客户端收到响应并处理它。
  • 每个以太网适配器都有一个全球唯一的48位地址。

  • 每台因特网主机都运行实现TCP/IP协议的软件。

  • 因特网的客户端和服务器混合使用套接字接口函数和Unix I/O函数来进行通信。

  • 套接字接口

sockaddr_in的16字节结构

  1. sin_family成员是AF_INET
  2. sin_port成员是一个16位的端口号
  3. sin_addr成员是一个32位的IP地址。
  4. IP地址和端口号总时以网络字节顺序(大端法)存放的。
  5. _in是互联网络的缩写,不是输入input的缩写。
  • Web服务器

    Web服务器使用HTTP协议和它们的客户端(浏览器等)彼此通信。

并发编程

逻辑控制流在时间上重叠,那么它们就是并发的。并发出现在计算机系统的许多不同层面上。

使用应用级并发的应用程序称为并发程序。现代操作系统提供了三种基本的构造并发程序的方法:

  1. 进程。每个逻辑控制流都是一个进程,由内核来调度和维护。因为进程 有独立的虚拟地址空间,想要和其他流通信,控制流必须使用某种显式的进程间通信 (interprocess communication, IPC) 机制。
  2. I/O 多路复用。在这种形式的并发编程中,应用程序在一个进程的上下文中显式地调度它们自己的逻辑流。逻辑流被模型化为状态机,数据到达文件描述符后,主程序显式地从一个状态转换到另一个状态。因为程序是一个单独的进程,所以所有的流都共享同一个地址空间。
  3. 线程。线程是运行在一个单一进程上下文中的逻辑流,由内核进行调度。是其他两种方式的混合体,像进程流一样由内核进行调度,而像I/O 多路复用流一样共享同一个虚拟地址空间。
  • 12.1基于进程的并发编程

  1. 构造并发程序最简单的方法就是用进程。
  2. 一个构造并发服务器的自然方法就是,在父进程中接受客户端连接请求,然后创建一个新的子进程来为每个新客户端提供服务。
  • 第一步:服务器接受客户端的连接请求;

  • 第二步:服务器派生一个子进程为这个客户端服务;

  • 第三步:服务器接受另一个连接请求;

  • 基于进程的并发服务器

  • 第四步:服务器派生另一个子进程为新的客户端服务。基于进程的并发 echo 服务器.父进程派生一个子进程来处理每个新的连接请求:

Posix线程

Posix线程是C程序中处理线程的一个标准接口。

万能函数:

void func(void parameter)
typedef void (uf)(void para)

创建线程

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)

3、终止线程

  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);

五、回收已终止线程的资源

pthread_join函数:

#include <pthread.h>

int pthread_join(pthread_t tid,void **thrad_return);

六、分离线程

pthread_detach函数

#include <pthread.h>

void pthread_detach(pthread_t tid);
功能:分离可结合线程tid。

七、初始化线程

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));

第四节 多线程程序中的共享变量

  1. 线程存储器模型
  2. 将变量映射到存储器
  3. 共享变量

12.5 用信号量同步线程

  • 进度图

进度图转换规则:

  • 合法的转换是向右或者向上,即某一个线程中的一条指令完成
  • 两条指令不能在同一时刻完成,即不允许出现对角线
  • 程序不能反向运行,即不能出现向下或向左
  • 而一个程序的执行历史被模型化为状态空间中的一条轨迹线。

线程循环代码的分解:

  • H:在循环头部的指令块
  • L:加载共享变量cnt到线程i中寄存器%eax的指令。
  • U:更新(增加)%eax的指令
  • S:将%eax的更新值存回到共享变量cnt的指令
  • T:循环尾部的指令块

临界区使用原则:有空让进、无空等待、多中择一、让权等待

  • 信号量

信号量定义:

type semaphore=record
count: integer;
queue: list of process
end;
var s:semaphore;
  • 使用信号量来实现互斥

第七节 并发问题

一、线程安全性

四个不相交的线程不安全函数类以及应对措施:

不保护共享变量的函数——用P和V这样的同步操作
保持跨越多个调用的状态的函数——重写
返回指向静态变量的指针的函数——①重写;②使用加锁-拷贝技术。

二、可重入性

1.显式可重入的

所有函数参数都是传值传递,没有指针,并且所有的数据引用都是本地的自动栈变量,没有引用静态或全剧变量。

2.隐式可重入的

调用线程小心的传递指向非共享数据的指针。

三、竞争

竞争发生的原因:

一个程序的正确性依赖于一个线程要在另一个线程到达y点之前到达它的控制流中的x点。也就是说,程序员假定线程会按照某种特殊的轨迹穿过执行状态空间,忘了一条准则规定:线程化的程序必须对任何可行的轨迹线都正确工作。
消除方法:

动态的为每个整数ID分配一个独立的块,并且传递给线程例程一个指向这个块的指针
四、死锁

一组线程被阻塞了,等待一个永远也不会为真的条件。

代码上传

咯咯:

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 2000行 30篇 400小时
第九周 832/950 17/17 140/140
第十周 968/1050 18/18 160/160
第十一周 1100/1200 19/19 180/180
第十二周 1197/1300 21/21 200/200

| 第十三周 | 1300/1400 | 22/22 | 210/210 | |

参考资料

原文地址:https://www.cnblogs.com/5314zkj/p/6160357.html