29、深入理解计算机系统笔记,并发编程(concurrent)(1)

1、如果逻辑控制流在时间上重叠,那么它们就是并发的。这种现象,称为并发(concurrency)。

2、为了允许服务器同时为大量客户端服务,比较好的方法是:创建并发服务器,为每个客户端创建各自独立的逻辑流。现代OS提供的常用构造并发的方法有:

进程和线程。

1)每个逻辑流都是一个进程,由内核来调度维护。每个进程都有独立的虚拟地址空间,控制流通过IPC机制来进行通信。

2)线程:运行在单一进程上下文中的逻辑流,由内核进行调度,共享同一进程的虚拟地址空间。

由于进程控制和IPC的开销较高,所以基于进程的设计比基于线程的设计慢。

常见IPC有:管道,FIFO,共享存储器,信号。

3、基于线程的并发编程

线程由内核自动调度,每个线程都有它自己的线程上下文(thread context),包括一个惟一的整数线程IDThread ID,TID),栈,栈指针,程序计数器,通用目的寄存器和条件码。每个线程和其他线程一起共享进程上下文的剩余部分,包括整个用户的虚拟地址空间,它是由只读文本(代码),读/写数据,堆以及所有的共享库代码和数据区域组成的,还有,线程也共享同样的打开文件的集合。

1)线程执行模型

wps_clip_image-20105

wps_clip_image-24647

wps_clip_image-16081

    线程不像进程那样,不是按照严格的父子层次来组织的。和一个进程相关的线程组成一个对等线程池(a pool of peers),独立于其他线程创建的线程(The threads associated with a process form a pool of peers, independent of which threads were created by which other threads.个人理解,这句是说独立于其他进程的线程池中的线程)。进程中第一个运行的线程称为主线程。对等(线程)池概念的主要影响是,一个线程可以杀死它的任何对等线程,或者等待它的任意对等线程终止;进一步来说,每个对等线程都能读写相同的共享数据。

2)关于posix线程示例,及其相关函数,参见原书13.3.2节中。这部分举的例子很经典,值得一读

3)分离线程

    在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死。在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。

示例程序

/* * echoservert.c - A concurrent echo server using threads */ /* $begin echoservertmain */ #include "csapp.h" void echo(int connfd); void *thread(void *vargp); int main(int argc, char **argv) { int listenfd, *connfdp, port, clientlen=sizeof(struct sockaddr_in); struct sockaddr_in clientaddr; pthread_t tid; if (argc != 2) { fprintf(stderr, "usage: %s <port>\n", argv[0]); exit(0); } port = atoi(argv[1]); listenfd = Open_listenfd(port); while (1) { connfdp = Malloc(sizeof(int)); *connfdp = Accept(listenfd, (SA *) &clientaddr, &clientlen); Pthread_create(&tid, NULL, thread, connfdp); } } /* thread routine */ void *thread(void *vargp) { int connfd = *((int *)vargp); Pthread_detach(pthread_self()); Free(vargp); echo(connfd); Close(connfd); return NULL; } /* $end echoservertmain */ 

你可能感兴趣的:(Concurrent)