Key-word: 线程, pthread_create, pthread_join, pthread_mutex_lock,pthread_mutex_unlock, pthread_cond_wait, pthread_cond_signal
基本概念:
在一个进程(可执行文件)中,想要同时运行几个函数,如何做?
用线程实现,线程可以看做是在一个进程中同时运行的几个函数。一个程序在一台机器上可以被同时执行多次,这些正在运行的程序就是进程。因此线程相对于函数类似于进程相对于程序。
进程和线程有根本上的不同。每个进程有其独立的数据空间、文件描述符和进程ID。而线程共享一个数据空间、文件描述符和进程ID。
1)数据空间
进程间的数据空间是独立的,可以理解为:同时运行的多个可执行文件内部所定义的变量、分配的内存不存在任何关系。
线程之间共享数据空间。可以理解为:线程是一个进程(可执行文件)中同时运行的几个函数,函数之间有共享的全局变量,因此可以用全局变量进行通信,也可以通过传递指向自己局部变量的指针进行通信。
2) 文件描述符
见chapter10。文件描述符的定义就是针对进程的,进程之间的文件描述符是独立的。
线程共享一个文件描述符。可以理解为:当一个线程将所在进程的标准输出由指向终端变为指向文件,则该进程内的其他线程也会将标准输出指向文件。
3) fork, exec, exit
所用的线程共享同一个进程。
fork创建一个新的进程,并把原调用进程的数据和代码复制给新的进程。如果某个线程调用了fork,只有调用fork的线程在新的进程中运行。
如果一个线程调用了exec,系统内核用一个新的进程取代当前的进程,从而该进程内所用的正在运行的线程都会结束。
如果一个线程执行了exit,那么整个进程都会结束,当然该进程内其他的线程也都结束了。
内容概述:
14.2 线程的创建和终止
用pthread_create创建一个新的线程,用pthread_joid等待某线程的终止。原型为:
Int pthread_create(pthread_t *thread, pthead_attr *attr, void *(*func)(void *), void *arg)
注意所创建线程(调用函数)的类型,参数和返回值都是void *类型的。
14.3线程间的分工合作
因为线程间共享全局变量,可以用全局变量来通信,但如何保证线程对全局变量的访问时互斥的?用互斥锁实现。下面是互斥锁的两个系统调用:
Int Pthread_mutex_lock(pthread_mutex_t*mutex)
用来锁住指定的互斥量。如果互斥量是开放的,它被锁住,并只能由调用线程来管理。如果此时互斥锁已经被其他的线程锁住,调用线程将挂起等待此互斥量被解锁。
Int pthread_mutex_unlock(pthread_mutex_t *mutex )
该函数给指定的互斥量解锁。
线程间通信的另一种方法是传递本地变量的指针,这样做既避免了对互斥量的依赖,又消除了全局变量。
14.6 线程间互通消息
又介绍了线程间通信的另外一种方式:使用条件变量。
Int pthtread_cond_wait( pthread_cond_t*cond, pthread_mutex_t *mutex)
该函数使线程挂起直到另一个线程调用pthread_cond_signal通过条件变量发出消息。Pthread_cond_wait函数总是和互斥锁一起使用。此函数先自动释放指定的锁,然后等待条件变量的变化。
Int pthread_cond_signal( pthread_cond_t*cond )
通过条件变量cond发消息。
利用以上介绍的互斥量、条件变量实现twordcount4.c。下面给出大致流程图(假设线程t1比t2先计数完):
14.6 多线程的Web服务器
对比chapter12的Web服务器,主要是用pthread_create代替fork,来实现同时执行客户端不同的请求。
且此处建立的是独立线程( DetachedThreads)。独立线程无需返回,也就是无需再调用pthread_wait来等待线程终止,当独立线程执行完毕后,自动释放所占用的资源。