zoukankan      html  css  js  c++  java
  • linux多线程和锁

    第一部分 多线程 
    第二部分 互斥锁 
    第三部分 条件变量 
    第四部分 读写锁 
    第五部分 自旋锁 
    第六部分 线程壁垒 
    第七部分 记录锁

      
    第一部分 多线程
      
    Linux 线程的创建: 
    int pthread_create ( pthread_t *tid, const pthread_attr_t *attr, void *(*func) (void *), void *arg); 
    tid:返回的线程id 
    attr:创建线程的属性可以为NULL,也可以在运行时再改变 
    func:线程运行的callback函数 
    arg:传给callback函数的参数 
    主要属性简要说明: 
    PTHREAD_CREATE_DETACH :表示同步脱离,且在退出时自行释放所占用的资源, 此时线程不能用pthread_join()来同步,这个属性可以在线程运行时调用pthread_detach()来设置,而一旦设置为PTHREAD_CREATE_DETACH状态(不论是创建时设置还是运行时设置)则不能再恢复到PTHREAD_CREATE_JOINABLE(默认属性)状态。 
    int pthread_detach (pthread_t tid); 
    说明:线程默认终止的时候资源不释放需要主进程调用pthread_join函数才能释放(类似于僵死进程和waitpid函数), pthread_detach 使得线程终止即释放资源,主进程不需要调用pthread_join函数 
      
    线程退出情形: 
    1) 正常return退出 
    2) 被其它线程调用pthread_cancel取消 
    3) 调用pthread_exit 退出,其中参数为函数退出时返回的数据 
    int pthread_join (pthread_t thread, void **rval_ptr); 
    阻塞直到指定线程终止, 并返回线程的返回值。 
    注意pthread_join函数操作的线程必须不是DETACHED线程。 
    rval_ptr返回值设置: 
    1) 如果线程正常return,则设置为return的值 
    2) 如果线程被取消则设置为PTHREAD_CANCELED 
    3) 如果线程调用pthread_exit退出则为pthread_exit 的参数 
    退出函数设置: 
    当线程退出时,可以设置一组退出函数类似于进程的atexit 
    void pthread_cleanup_push (void (*rtn)(void *),   void *arg); 
    void pthread_cleanup_pop (int execute); 
    退出函数执行条件: 
    1) 线程调用pthread_exit 退出 
    2) 线程被其它线程取消 
    3) 调用pthread_cleanup_pop 并且参数非0 
    注意:函数正常return 不调用退出函数 
      
    线程的取消: 
    int pthread_cancel (pthread_t tid);发送终止信号给thread线程,如果成功则返回0,否则为非0值。发送成功并不意味着thread会终止 . 
    int pthread_setcancelstate (int state, int *oldstate) 
    设置本线程对cancel信号的反应. 
    state有两种值: 
    1)PTHREAD_CANCEL_ENABLE(缺省)收到信号后设为CANCLED状态2)PTHREAD_CANCEL_DISABLE,忽略CANCEL信号继续运行 
    old_state如果不为NULL则存入原来的cancel状态以便恢复。 
    int pthread_setcanceltype (int type, int *oldtype) 
    设置本线程取消动作的执行时机,仅当cancel状态为Enable时有效 
    type由两种取值: 
    1) PTHREAD_CANCEL_DEFFERED表示收到信号后继续运行至下一个取消点再退出 
    2) PTHREAD_CANCEL_ASYCHRONOUS表示立即执行取消动作(退出); 
    oldtype如果不为NULL则存入原来的取消动作类型值。 
    void pthread_testcancel (void) 
    检查本线程是否处于canceld状态,如果是,则执行取消动作,否则直接返回。 
    此函数用来设置取消点

      
    线程私有数据(Thread-specific Data,或TSD) 
    int pthread_key_create (pthread_key_t *keyptr, void (*destructor) (void *value)); 
    该函数从TSD池中分配一项,将其值赋给keyptr供以后访问使用。如果destr_function不为空,在线程退出(pthread_exit())时将以key所关联的数据为参数调用destr_function(),以释放分配的缓冲区。 
    int pthread_key_delete (pthread_key_t key)这个函数并不检查当前是否有线程正使用该TSD,也不会调用清理函数,而只是将TSD释放以供下一次调用pthread_key_create()使用。 
    TSD的读写: 
    int pthread_setspecific (pthread_key_t key, const void *pointer) 
    写入,将pointer的值(不是所指的内容)与key相关联 
    void * pthread_getspecific (pthread_key_t key) 
    读出函数,将与key相关联的数据读出来。 
    说明:不同线程对同一个key的访问互不冲突。 

      
    pthread_once_t initflag = PTHREAD_ONCE_INIT; 
    int pthread_once (pthread_once_t *initflag, void  (*initfn)(void)); 
    多个线程调用,保证仅执行一次的函数,其中initflag不可以是局部变量。 
    获得线程本身id 
    pthread_t pthread_self (void); 
    线程id 比较int pthread_equal (pthread_t tid1, pthread_t tid2); 相等返回非0 
      
    线程IO操作: 
    如果多个线程并发访问同一个文件的时候可以使用pread或pwrite它们保证了原子操作 
    其它: 
    pthread_kill_other_threads_np() 强行杀死所有线程,它没有通过pthread_cancel()来终止线程,而是直接向管理线程发“进程退出”信号,使所有其他线程都结束运行,而不经过cancel动作,当然也不会执行退出回调函数 ,一般用在exec执行前来结束所有正在运行的线程。 
    线程属性操作(略) 

      
    第二部分 互斥锁
      
    Mutex基本操作函数: 
    初始化方法: 
     1)  如:static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER 使用默认属性 
     2)  调用pthread_mutex_init 方法,可以同时设定属性 
    销毁方法: 
    int pthread_mutex_destroy (pthread_mutex_t *mutex); 
    销毁一个互斥锁即释放它所占用的资源,并且要求锁当前是非锁定状态。由于在Linux中,互斥锁并不占用任何资源,它除了检查锁状态以外(锁定状态则返回EBUSY)没有其它动作。 
    互斥锁基本操作: 
    int pthread_mutex_lock (pthread_mutex_t *mutex); 
    int pthread_mutex_trylock (pthread_mutex_t *mutex); 
    int pthread_mutex_unlock (pthread_mutex_t *mutex); 
      
    Mutex基本属性操作: 
    int pthread_mutexattr_init (pthread_mutexattr_t *attr); 
    int pthread_mutexattr_destroy (pthread_mutexattr_t   *attr); 
    int pthread_mutexattr_getpshared (const   pthread_mutexattr_t * restrict attr, int *restrict   pshared); 
    int pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared); 
    说明: 
    1) Mutex默认只能用于多线程间互斥操作即属性为PTHREAD_PROCESS_PRIVATE ,如果用于多进程操作必须修改其属性为PTHREAD_PROCESS_SHARED 
    2) pthread_mutexattr_init 和 pthread_mutexattr_destroy 函数用来初始化或析构pthread_mutexattr_t 结构 但由另外两个函数来设置PTHREAD_PROCESS_SHARED 属性 
    3) 注意有些平台不支持多进程间互斥锁. 
    其它属性简要介绍: 
    1) PTHREAD_MUTEX_TIMED_NP: 普通锁(缺省值)。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。 
    2) PTHREAD_MUTEX_RECURSIVE_NP:嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争 
    3) PTHREAD_MUTEX_ERRORCHECK_NP: 检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁 
    4) PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,仅等待解锁后重新竞争。 
      
    使用互斥锁注意事项: 
    1) Linux 中实现的POSIX线程锁都不是取消点,因此,线程被取消后不会因为收到取消信号而离开加锁等待状态。 
    2) 如果线程在加锁后解锁前被取消,锁将永远保持锁定状态,因此如果在关键区段内有取消点存在,或者设置了异步取消类型,则必须在退出回调函数中解锁。 
    3) 这个锁机制同时不是异步信号安全的,所以不应该在信号处理函数中使用互斥锁,否则容易造成死锁。 

      
    第三部分 条件变量 
      
    条件变量主要的目的是等待直到条件成立。类似于某些系统的Event。 
    它主要包括两个动作: 
    1)  一个线程等待“条件变量的条件成立”而挂起; 
    2) 另一个线程使“条件成立”。 
    注意:为了防止竞争条件变量的使用总是和一个互斥锁结合在一起 
      
    条件变量基本操作函数:初始化方法: 
     1)  如:static pthread_cond_t  cond=PTHREAD_COND_INITIALIZER默认属性 
     2)  调用pthread_cond_init 方法,可以同时设定属性 
    销毁方法: 
    int pthread_cond_destroy (pthread_cond_t *cond); 
    只有在没有线程在该条件变量上等待的时候才能注销这个条件变量,否则返回EBUSY。 
    等待操作: 
    int pthread_cond_wait (pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex) 
    int pthread_cond_timedwait (pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout); 
    产生信号操作: 
    int pthread_cond_signal (pthread_cond_t *cond);激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个 
    int pthread_cond_broadcast (pthread_cond_t *cond);激活所有等待线程 
      
    属性基本操作(类似于互斥锁) 
    int pthread_condattr_init (pthread_condattr_t *attr); 
    int pthread_condattr_destroy (pthread_condattr_t   *attr); 
    int pthread_condattr_getpshared (const   pthread_condattr_t * restrict attr, int *restrict   pshared); 
    int pthread_condattr_setpshared (pthread_condattr_t   *attr, int pshared); 
      
    使用条件变量注意事项: 
    1) pthread_cond_wait()和pthread_cond_timedwait()都被实现为取消点, 在该处等待的线程将立即重新运行 2) 被取消后它首先获的互斥锁,然后执行取消动作。即互斥锁是保持锁定状态的,因而需要定义退出回调函数来为其解锁。 
    使用举例: 
    { 
    pthread_mutex_lock (&mutex)); 
    pthread_cond_wait (&cond,& mutex); 
    pthread_mutex_unlock (&mutex); 

     


    第四部分 读写锁 
      
    读写锁基本特点: 
    1)如果没有线程持有写锁, 那么获得读锁就会成功 
    2)如果没有线程持有读锁和写锁,那么获得写锁才会成功 
    它常被应用于频繁读而很少修改得情况。 
      
    读写锁初始化或销毁: 
    static pthread_rwlock_t rwLock = PTHREAD_RWLOCK_INITIALIZER 
    int pthread_rwlock_init (pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t  *restrict attr); 
    int pthread_rwlock_destroy (pthread_rwlock_t *rwlock); 
    获得锁或释放锁操作 
    int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock); 
    int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock); 
    int pthread_rwlock_unlock (pthread_rwlock_t *rwlock); 
    int pthread_rwlock_tryrdlock (pthread_rwlock_t   *rwlock); 
    int pthread_rwlock_trywrlock (pthread_rwlock_t   *rwlock); 
    属性设置 
    int pthread_rwlockattr_init (pthread_rwlockattr_t   *attr); 
    int pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr); 
    int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * restrict attr, int *restrict pshared); 
    int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared); 
      
    第五部分 自旋锁
      
    自旋锁基本特点: 
    1) 在用户空间实现, 不需要做内核切换 
    2) 忙-等待,也就是说在获得不了锁的情况下仍然占用CPU资源 
    3) 要求关键区域执行时间必须非常得短小,并且不允许睡眠, 如果执行时间超过了其它线程等待的时间片(即时间片用完,发生了线程切换), 则用自旋锁就失去了意义,并空耗了CPU时间, 这种情况不防称为失败的等待
    4) 如果失败的等待非常多会严重影响系统的性能。此时就应该选用其它锁 
      
    基本操作函数: 
    1) 初始化方法: __pshared大于0表示用在多进程间 
      int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared) 
    2)销毁方法: 
    int pthread_spin_destory (pthread_spinlock_t * __lock) 
    3) 锁操作方法: 
    int  pthread_spin_lock (pthread_spinlock_t * __lock) 
    int  pthread_spin_trylock (pthread_spinlock_t * __lock) 
    int  pthread_spin_unlock (pthread_spinlock_t * __lock) 

      
    第六部分 线程壁垒 
      
    壁垒(barrier)基本说明: 
    主要用来等待某些数量的线程在壁垒处集合。在设定的数目达到之后,解锁这些线程,让它们继续运行。 
    而pthread_join() 方法是等待线程结束 
      
    壁垒(barrier)基本操作函数: 
    初始化: count表示必须调用pthread_barrier_wait线程的个数 
    int pthread_barrier_init (pthread_barrier_t  *barrier, const pthread_barrierattr_t *attr, unsigned int count); 
    销毁函数: 
    int pthread_barrier_destroy (pthread_barrier_t *barrier) 
    同步点函数: 
    int pthread_barrier_wait (pthread_barrier_t *barrier); 
      
    第七部分 记录锁
      
    记录锁主要用于不同进程间锁定文件,它可以锁定整个文件或部分字节数据 
    注意:记录锁是面向进程的,因此不能用于线程间。 
    主要操作函数如下: 
    int fcntl (int filedes, int cmd, ... /* struct   flock *flockptr */ ); 
    其中: 
    struct flock 
    { 
      short l_type; /* F_RDLCK(共享读), F_WRLCK(排斥写), F_UNLCK(解锁) */ 
      off_t l_start; /* 相对于l_whence的偏移(字节单位) */ 
      short l_whence; /* SEEK_SET, SEEK_CUR, or SEEK_END */ 
       off_t l_len; /* 锁定长度,0表示锁定到文件结束 */ 
       pid_t l_pid; /* 用于 F_GETLK */ 
    }; 
    cmd: 
    F_GETLK: 获得锁状态 
    F_SETLK: 非阻塞获得锁失败返回EAGAIN 
    F_SETLKW: 阻塞获得锁, 可被信号唤醒。 
      
    记录锁用法说明: 
    1) 当进程终止或关闭描述符的时候,锁自动释放。 
     a.   fd1 = open (pathname, ...);        b.  fd1 = open (pathname, ...); 
           read_lock(fd1, ...);                           read_lock(fd1, ...); 
           fd2 = dup(fd1);                                 fd2 = open (pathname, ...) 
           close(fd2);                                        close(fd2); 
    2) 当fork子进程的时候,锁不被继承。 
    3) 当执行exec的时候锁不释放。设置了close-on-exec的除外 
    4) 有Advisory和Mandatory锁 
        系统中默认是Advisory锁, 当一个进程获得锁进行读写的时候,并不能阻止其它进行不去获得锁直接进行读写, 为了保证操作的正确性, 所有操作文件的进程必须按照规则, 首先获得锁 然后才能进行读写。 
       Mandatory 锁保证了当一个进程获得锁进行读写得时候, 其它进行直接读写文件会失败。

  • 相关阅读:
    marquee基本语法和marquee的相关参数设置
    [转]FreeTextBox使用详解
    div+css三级下拉菜单无限制下拉
    让Flash在Firefox和IE下背景透明
    asp.net制作幻灯片
    图片连续滚动代码,左右连续,上下连续不间断滚动
    纯DIV+CSS下拉菜单
    连续滚动图片代码
    sql语句修改access中的字段类型,access数据类型大全!
    非常棒的图片连续滚动代码
  • 原文地址:https://www.cnblogs.com/wangfengju/p/6173118.html
Copyright © 2011-2022 走看看