UNIX网络编程----线程
一、概述
一个服务器的父进程accept一个连接,fork()一个子进程,该子进程处理与该连接对端的客户之间的通信。但是fork调用却存在一些问题。
1) fork是昂贵的。当今的实现使用称为写实复制的技术,用以避免在子进程切实需要自己的副本之前把父进程的数据空间按复制到子进程。然而即便有这样的优化措施,fork还是昂贵的。
2) fork返回之后斧子进程之间信息的传递需要进程间通信(IPC)机制,从父进程向子进程传递信息比较容易,但是相反的方向却不是那么容易。
线程有助于解决这两个问题,线程创建可能比进程的创建块10~100倍。
同一进程的所有线程共享相同的全局内存。这使得线程之间易于共享信息,然而伴随这种简易行而来的是同步问题
同一进程内的所有线程除了共享全局变量之外还共享:
1) 进程指令
2) 大多数数据
3) 打开的文件(即描述符)
4) 信号处理函数和信号处置
5) 当前工作目录
6) 用户ID和组ID
每个线程有各自的:
1) 线程ID
2) 寄存器集合,包括程序计数器和栈指针
3) 栈(用于存放局部变量和返回地址)
4) Errno
5) 信号掩码
6) 优先级
二、基本线程函数:创建和终止
1)#include <pthread.h>
Int pthread_create(pthread_t*tid,const pthread_attr_t *attr,void *(*func(void*)),void *arg);
创建一个线程时我们最后指定的参数是由该线程执行的函数及其参数。该线程通过调用这个函数开始执行,然后或者显示地终止(通过调用pthread_exit),或者隐式地终止(通过让函数返回)。该函数的地址由func参数指定,该函数的唯一调用参数是指针arg。如果我们需要给该函数传递多个参数,我们就得把他们打包成一个结构,然后把这个结构的地址作为单个参数传递给这个其实函数。
注意func和arg的声明。Func所指函数作为参数接受一个通用指针(void *),又作为返回值返回一个通用指针(void *).这使得我们可以把一个指针(它指向我们期望的任何 内容)传递给线程,又允许线程返回一个指针(它同样指向我们期望的任何内容)
返回成功为0,失败为非0.
2)#include <pthread.h>
Int pthread_join(pthread_t*tid,void **status);
我们可以通过这个函数等待一个给定线程终止,对比与UNIX进程,pthread_create类似于fork,pthread_join类似于waitpid.
必须知道你个要等待线程的tid,如果status指针为非空,来自所等待线程的返回值(一个指向某个对象的指针)将存入有status指向的位置。
3) pthread_t pthread_self(void);
获取自身的线程ID。类似于进程中的getpid函数。
4) pthread_detach函数
一个线程可能是可回合的,或者是可脱离的。当一个可汇合的线程终止时,它的线程ID和退出状态将留存待另一个线程对它调用pthread_join。此函数把指定的线程转变为脱离状态。
三、互斥锁
线程编程为并发编程或者并行编程,因为多个线程可以并发地运行且访问相同的变量。进程编程中不会发生这样的情况,但讨论在进程之间的共享内存区时,仍然会碰到同类问题。解决这个问题的方法为互斥锁。使用互斥锁来保护这个共享变量。访问该变量的前条件是持有该互斥锁。互斥锁是类型为pthread_mutex_t的变量。
1)#include <pthread.h>
Int pthread_mutex_lock(pthreaed_mutex_t*mptr);
Int pthread_mutex_unlock(pthread_mutex_t*mptr);
如果试图上锁已被另外某个线程锁住的一个互斥锁,本线程将被阻塞,直到该互斥锁被解锁为止。
如果某个互斥锁变量时静态分配的,我们就必须把它初始化为常值PTHREAD_MUTEX_INITIALIZER.如果我们在共享内存区分配一个互斥锁,那么必须通过调用pthread_mutex_init函数在运行时把它初始化。
四、条件变量
互斥锁适合于防止同时访问某个共享变量,但是我们需要另外某种在等待某个条件发生期间能让我们进入睡眠的东西。
需要一个让主循环进入睡眠,直到某个线程通知它有事可做才醒来的方法。条件变量结合互斥锁能够提供这个功能。互斥锁提供呼哧机制,条件变量提供信号机制。条件变量时类型为pthread_cond_t的变量。
Int pthread_cond_wait(pthread_cond_t *cptr,pthread_mutex_t*mptr);
Int pthread_cond_signal(pthread_cond_t *cptr);