网络编程之并发-多线程

接下来看看并发服务器的第二种方法:线程 

线程创建及运行 

 需要单独定义线程main函数,还需要请求操作系统在单独流中执行该函数 
  #include  
  int pthread_create( 
        pthread_t * restrict thread, const pthread_attr_t * restrict attr,  
        void * (* start_routine)(void *), void * restrict arg); 
 成功返回0,失败返回其他值 
thread 保存新建线程ID的变量地址值 
        attr 用于传递线程属性的参数,NULL为默认属性的线程 
        start_routine 线程的main函数,在单独执行流中执行的函数地址值 
        arg 通过第三个参数传递调用函数时包含传递参数信息的变量地址值 
         
        编译线程相关代码时,加-lpthread声明连接线程库,才能调用头文件pthread中声明的函数 

#include  
int pthread_join(pthread_t thread, void ** status); 
成功返回0,失败返回其他值 
thread 该参数ID的线程终止后才会从该函数返回 
status 保存线程的main函数返回值的指针变量地址值 
 
根据临界区是否引起问题,线程函数可以分为两类 
线程安全函数:被多个线程同时调用时也不会引发问题
非线程安全函数 
线程安全函数中同样可能存在临界区,可通过措施避免问题 

大多标准函数都是线程安全函数,定义非线程安全函数的同时,会提供具有相同功能的线程安全函数 
声明头文件前定义_REENTRANT宏,将函数改为对应线程安全函数调用 
通常在编译时加:如 gcc _D_REENTRANT mythread.c -o mthread -lpthread
线程安全函数通常加_r后缀  

 

每个进程有独立内存:数据区、堆、栈 
  多个线程共享数据区和堆、有独立的栈 
        这时就存在一个问题,多个线程同时访问一个变量,变量的值会怎么改变呢? 
    为了避免这个情况,我们使用线程同步机制 
同步:线程访问变量时应该阻止其他线程访问,直到该线程完成运算 

临界区:函数内同时运行多个线程时引起问题的多条语句构成的代码块
 
 
  需要同步的情况:  
同时访问同一内存空间时发生的情况 
需要指定访问同一内存空间的线程执行顺序的情况 
 
 
同步的两种方法:互斥量、信号量 
 
 互斥量:作为锁,不允许多个线程同时访问
 互斥量的创建和销毁 
 #include  
 int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr);   
 int pthread_mutex_destroy(pthread_mutex_t * mutex); 
 成功返回0,失败返回其他值 
 mutex 互斥量的变量地址值 
 attr 传递互斥量属性,没有时设为NULL 
 
 可以通过宏向第二个参数传递NULL【不推荐,很难发现发生的错误】 
 pthread_mutex_t * mutex = PTHREAD_MUTEX_INITIALIZER 
  
 互斥量锁住和释放 
 #include  
 int pthread_mutex_lock(pthread_mutex_t * mutex);  

        //临界区

 int pthread_mutex_unlock(pthread_mutex_t * mutex); 
  
 A线程进入临界区前调用pthread_mutex_lock,如果发现其他线程已进入临界区, 
 则pthread_mutex_lock函数不会返回,直到临界区里面的B线程调用pthread_mutex_unlock函数 
 退出临界区为止。B线程调用pthread_mutex_unlock函数之前,A线程一直处于阻塞状态 
 如果B线程退出临界区时忘记调用B线程调用pthread_mutex_unlock函数,则其他函数  
 为了进入临界区调用的B线程调用pthread_mutex_lock函数无法摆脱阻塞状态,这种 
      情况成为死锁 
       
 用互斥锁划分临界区,根据实际情况划分临界区大小 
 
信号量 
 信号量创建和销毁 
 #include  
 int sem_init(sem_t *sem, int pshared, unsigned int value); 
 int sem_destroy(sem_t *sem); 
 成功返回0,失败返回其他值 
  
 sem 信号量的变量地址值
 pshared 传递其他值时创建可由多个进程共享的信号量,传递0时创建只允许一个进程内部使用的信号量 
 value 指定新创建的信号量初始值 
 
 相当于互斥量lock、unlock的函数 
 #include  
 int sem_post(sem_t * sem); 
 int sem_wait(sem_t * sem); 
 成功返回0,失败返回其他值 
 sem 传递保存信号量读取值的变量地址值,传递给sem_post时信号量加一, 
     传递给sem_wait时信号量减一 
 
      调用sem_init函数时,操作系统将创建信号量对象,此对象中记录“信号量值”整数, 
      该值在调用sem_post函数时加一,调用sem_wait函数时减一,但信号量值不能小于 0 
sem_wait(&sem);//信号量变为0 
//临界区 
sem_post(&sem);//信号量变为1 
 
调用sem_wait函数进入临界区的线程在调用sem_post函数前不允许其他线程进入临界区 
信号量在0/1之间跳转,因此称为二进制信号量  

  

线程的销毁:

  线程不会自动销毁,销毁方法: 
 调用pthread_join函数 
 调用pthread_detach函数  
 调用pthread_join函数时,不仅会等待线程终止,还会引导线程销毁 
 线程终止前,调用该函数的线程将进入阻塞状态。 
 
 #include  
 int pthread_detach(pthread_t thread); 
 成功返回0,失败返回其他值 
 thread 终止的同时需要销毁的线程ID
 调用此函数不会引起线程终止或进入阻塞状态,可用该函数引导销毁线程创建的内存空间  
 调用该函数后不能 在针对相应线程调用pthread_join函数  
 
 有其他方法可以在创建线程时指定销毁时机,有兴趣的自行百度   

你可能感兴趣的:(网络编程,网络编程,并发,线程)