2018-2019-1 20165330 《信息安全系统设计基础》第八周学习总结
学习目标
- 掌握三种并发的方式:进程、线程、I/O多路复用
- 掌握线程控制及相关系统调用
- 掌握线程同步互斥及相关系统调用
学习内容
基于进程的并发编程
- 用进程构造并发程序
- 服务器接收客户端的连接请求
- 服务器派生一个子进程为这个客户端服务
- 服务器接受另一个连接请求
- 服务器派生另一个子进程为新的客户端服务
- 服务器接收客户端的连接请求
基于I/O多路复用的并发编程
- I/O多路复用
- 使用
select
函数,要求内核挂起进程,只有在一个或多个I/O事件发生后,才将控制返回给应用程序 select
函数#include <sys/select.h> int select(int n,fd_set *fdset,NULL,NULL,NuLL); FD_ZERO(fd_set *fdset); /* Clear all bits in fdset */ FD_CLR(int fd,fd_set *fdset); /* Clear bit fd in fdset */ FD_SET(int fd,fd_set *fdset); /* Turn on bit fd in fdset */ FD_ISSET(int fd,fd_set *fdset); /* Is bit fd in fdset on? */ 处理描述符集合的宏
- 使用
- 并发事件驱动服务器
- 每个输入事件都会引发一个从当前状态到下一状态的转移。
- 服务器使用I/O多路复用,借助
select
函数检测输入事件的发生。当每个已连接描述符准备好可读时,服务器就为相应的状态机执行转移。 - 对于每个新的客户端k,基于I/O多路复用的并发服务器会创建一个新的状态机Sk,并将它和已连接描述符dk联系起来。
基于线程的并发编程
-
创建线程
#include <pthread.h> typedef void *(func)(void *); int pthread_create(pthread_t *tid,pthread_attr_t *attr,func *f,void *arg);
-
初始化线程
#include <pthread.h> pthread_once_t once_control = PTHREAD_ONCE_INIT; int pthread_once(pthread_once_t *once_control,void (*init_routine)(void));
-
获取线程ID
#include <pthread.h> pthread_t pthread_self(void);
-
终止线程
- 显示地终止
#include <pthread.h> void pthread_exit(void *thread_return);
- 以当前线程ID为参数调用
pthread_cancel
函数终止当前线程#include <pthread.h> int pthread_cancel(pthread_t tid);
- 显示地终止
-
回收已终止的资源
#include <pthread.h> int pthread_join(pthread_t tid,void **thread_return);
线程同步互斥
- 信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作
- P操作:如果s是非零的,那么P将减1,并且立即返回。如果s为零,那么就挂起这个线程,知道s变为非零,而一个V操作 会重启这个线程。在重启之后,P操作将s减1,并将控制返回给调用者
- V操作:V操作将s加1。如果有任何线程阻塞在P操作等待s变成非零那么V操作会重启这些线程中的一个,然后该线程将s减1,完成它的P操作。
- Linux下编译命令
gcc XXX.c -lpthread -o XXXX
gcc XXX.c -pthread -o XXXX
- 线程互斥
- 多个线程之间有共享资源时会出现互斥现象。
- 当一个进程进入临界区使用临界资源时,另一个进程(线程)必须等待, 当占用临界资源的进程退出临界区后,另一进程才允许去访问此临界资源。
#include <pthread.h> int pthread_mutex_destory(pthread_mutex_t *mutex); int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- 线程同步
- 程相互等待
- 当线程A使用某个对象,而此对象又需要线程B修改后才能符合本线程的需要,此时线程A就要等待线程B完成修改工作
#include <pthread.h> int pthread_cond_destroy(pthread_cond_t *cond); int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr); pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
- 互斥锁
- 获得锁的线程可以完成“读-修改-写”的操作,然后释放锁给其它线程
- 没有获得锁的线程只能等待而不能访问共享数据
#include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); pthread_mutex_t unlock(pthread_mutex_t *mutex);
- 线程不安全函数类
- 不保护共享变量的函数
- 保持跨越多个调用的状态的函数
- 返回指向静态变量指针的函数
- 调用线程不安全函数的函数
- 线程与进程
功能 | 进程 | 线程 |
---|---|---|
创建 | fork | pthread_create |
等待 | wait/waitpid | pthread_join |
终止 | exit/_exit | pthread_exit |
ID | getpid/getppid | pthread_self |
互斥 | semaphore | mutex/semaphore |
同步 | semaphore | cond var/semaphore |