第十二章 并发编程

-------------------------------------------------------
Thu 22 Feb 12:21:12 GMT 2018
-------------------------------------------------------
第十二章 并发编程
-------------------------------------------------------
使用应用级并发的应用程序称为并发程序(concurrent program)
.现代操作系统提供3个基本的构造并发程序的方法:

+ 进程
+ I/O多路复用。(i/o multiplexing)
+ threads


12.1 Concurrent programming with processes

The simplest way to build a concurrent program is
with processes, using familiar functions such as "fork",
"exec", and 'waitpid'.

12.2 基于I/O多路复用的并发编程

基本思路是使用select函数,要求内核挂起进程,只有在一个或
多个I/O事件发生后,才将控制返回应用程序。

#include <sys/select.h>
int select(int n,fd_set *fdset,NULL,NULL,NULL);

返回已准备好的描述符的非零的个数,error 为 -1.

FD_ZERO(fd_set *fdset); //clear alll 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


select处理类型为fd_set的集合,也叫做描述符集合。该集合是
一个大小为n的位向量。

12.3 基于线程的并发编程

每个线程都有自己的线程上下文(thread context),包括哟个唯
一的整数线程ID(thread ID, TID,栈,栈指针,程序计数器,通用
目的寄存器和条件码。

12.3.2 Posix 线程(Pthreads)
它是c程序中处理线程的一个标准接口。

#include <pthread.h>
typedef void *(func)(void *);

int pthread_create(pthread_t *tid,pthread_addr_t *attr
, func *f, void *arg);

新线程可以通过调用pthread_self函数来获得它自己的TID,

pthread_t pthread_self(void);


12.3.4 终止线程

+ 当顶层的线程例程返回时,线程会隐式地终止。
+ 通过调用pthread_exit函数,显示地终止。如果主线程调用
pthread_exit,它会等待所有其他对等线程终止,然后再终止
主线程和整个进程,返回值为thread_return.

void pthread_exit(void *thread_return);

+ 某个对等线程调用Linux的exit函数,该函数终止进程及所有
与该进程相关的线程。
+ 另一个对等线程通过以当前线程ID作为参数调用
pthread_cancel函数来终止当前线程。

int pthread_cancel(pthread_t tid);

12.3.5 回收已终止线程的资源

线程通过调用pthread_join function等待其他线程终止。

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

12.3.6 分离线程(Detaching Threads)

At any point in time a thread is joinable or detached.
A joinable thread can be reaped and killed by other thread
. Its memory resources(such as the stack) are not freed
until it is reaped by another thread.

In contrast, a detached thread cannot be reaped or
killed by other threads. Its memory resources ard freed
automatically by the system when it terminates.

默认情况下,线程被创建成可结合的。用pthread_detach函数
分离线程。

int pthread_detach(pthread_t tid);

12.3.7 初始化线程

函数pthread_once允许初始化与线程相关的状态:

pthread_once_t once_control = PTHREAD_ONCE_INIT;

int pthread_once(pthread_once_t *once_control,
void (*init_routine)(void));

once_control变量是一个全局或者静态变量,总是被初始化为
PTHREAD_ONCE_INIT.

12.4 Shared variables in threaded programs

registers are never shared,whereas virtual memory is
always shard.


12.4.3 Shared variables

We say that a variables V is shared if and only if one
of its instances is referenced by more than one thread.


12.5 信号量同步线程

12.5.2 semaphore(信号量)

信号量s是具有非负整数的全局变量,只有两种操作:(P,V):

+ s的初始值为1

+ P(s): 如果s非零,p将s减1,并立即返回。如果s为0,就
挂起这个线程,直到s变为0,而一个V操作会重启这个线
程。在重启后,P操作将s减1,并将控制返回调研者

+ V(s): V操作将s加1。如果有线程阻塞在P操作等待s变为
非零,那么V操作会重启这些线程中的一个,然后该线程
将s减1,完成它的操作。

#include <semaphore.h>

int sem_init(sem_t *sem,0,unsigned int value);
int sem_wait(sem_t *s); // P(s)
int sem_post(set_t *s); // V(s)

以提供互斥为目的的二元信号量常常也称为互斥锁(mutex).


12.5.4 利用信号量来调度共享资源

1,生产者-消费者问题
2,读者-写着问题

12.5.5 综合:基于预线程化的并发服务器(pre_threading)

+ 函数pthread_once用法:

int byte_cnt;
sem_t mutex;
void init_echo_cnt(void)
{
sem_init(&mutex,0,1);
byte_cnt = 0;
}
pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_once(&once,init_echo_cnt);


12.6 使用线程提高并行性

-------------------------------------------------------
Fri 2 Mar 13:49:52 GMT 2018

posted @ 2018-03-28 23:35  孤灯下的守护者  阅读(106)  评论(0编辑  收藏  举报