您的位置:首页 > 运维架构 > Linux

linux 线程 线程同步

2016-02-15 23:36 246 查看
        因为线程独自拥有的只有栈,其他的区域线程共同拥有。并且对共享区域的操作并不都是原子的。对共享区域的操作顺序又是不确定的。就像创建两个文件描述符同时指向

同一文件,并且连续向文件中写入那么写的东西可能是乱七八糟的。这时就需要线程对共享区的同步。

        而另一种情况是,多个线程的指令执行顺序需要同步。(这与访问区域无关,纯粹是指令顺序的方面)

临界区:

    保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共

享资源进行访问。如果有多个线程试图同时访问临界区,那么 在有一个线程进入后其他所

有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释

放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。

    临界区的选定因尽可能小,如果选定太大会影响程序的并行处理性能。    

    那么下面介绍一些线程同步的方法。

    

1>  互斥量

互斥量有两种状态  锁被占用  所空闲

int pthread_mutex_destroy(pthread_mutex_t *mutex);  //销毁一个锁  如果malloc分配的锁  要在free前销毁  否则可能会出现锁泄露

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);//初始化一个锁  attr == NULL则用默认属性

int pthread_mutex_lock(pthread_mutex_t *mutex);  //加锁  如果锁被占用则函数阻塞知道锁被释放

int pthread_mutex_trylock(pthread_mutex_t *mutex);  //尝试加锁  如果锁是空闲的  则加锁  否则返回错误编号而不阻塞

int pthread_mutex_unlock(pthread_mutex_t *mutex);  //解锁

 int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);//限时阻塞加锁函数

如果在时间耗尽内还未取得锁那么返回错误编号  可以让程序不会永远阻塞  

返回值:成功返回0  出错返回错误编号

如果锁是静态分配的还可以直接赋值  PTHREAD_MUTEX_INITIALIZER;(malloc则不能直接这样做必须用初始化函数)

pthread_mutex_t  锁结构数据类型  这个结构貌似是透明的上面一组函数用于操作它

attr是锁属性下一篇再谈  若使用NULL则为默认锁属性

死锁:

1.同一个线程在拥有A锁的情况下再次请求获得A锁

2.线程一拥有A锁,请求获得B锁;线程二拥有B锁,请求获得A锁

死锁导致的结果是什么?

解决方法  用两个锁时可以按相同的顺序加锁 如果锁的数量过多那么程序会变得异常复杂

2>读写锁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);//可以解 读锁 或  写锁

返回值  成功返回0  否则 返回错误码

用法与互斥量类似不再赘述

       互斥量有两种状态,而读写锁有三种状态。 读锁  写锁  空闲

       若写锁已加   则试图加锁的线程阻塞

       若读锁已加   则加读锁成功   加写锁阻塞知道所有读锁解除(可以多个进程同时拥有读锁)

      随具体实现不同 

      若对读锁已加  请求写锁  再请求加读锁则可能阻塞   这样就防止写锁总是得不到请求而长期阻塞(未能证实  redhat 6.0)

      加读锁的数量可能有限  (未能证实  redhat6.0  )

带有超时的读写锁

      int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock,

              const struct timespec *restrict abs_timeout);

     int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock,

              const struct timespec *restrict abs_timeout);

      *避免加锁时永久阻塞

3>条件变量            

互斥量存在的问题:从本质上说互斥量就是一把锁,互斥量串行执行,能[b]确保每次只有一个线程访问。[/b]互斥量是线程程序必需的工具,但它们并非万能的。例如,如果线程正在轮询等待共享数据内某个条件出现,那会发生什么呢?它可以重复对互斥对象锁定和解锁,每次都会检查共享数据结构,以查找某个值。但这是在浪费时间和资源,而且这种繁忙查询的效率非常低。同样,在每次检查之间让线程短暂地进入睡眠,比如睡眠3s,但是因此线程代码就无法最快作出响应。

    问题的解决: 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,条件变量常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。

int pthread_cond_destroy(pthread_cond_t *cond);

int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);

       

int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);

int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

int pthread_cond_broadcast(pthread_cond_t *cond);

int pthread_cond_signal(pthread_cond_t *cond);

pthread_ PTHREAD_COND_INITIALIZER;  //用于初始化静态的条件变量

条件变量的关键在于int pthread_cond_wait

这个api执行了三个动作

解锁 阻塞(这两个是原子的)加锁

前两个动作解除了  条件判断与阻塞之间的竞争条件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: