unix线程同步

来源:互联网 发布:windows api编程 编辑:程序博客网 时间:2024/05/28 06:04

线程同步

因为线程共享进程的存储空间,所以进程的栈 全局变量都可以被
线程所访问,但是又因为竞度问题,我们无法判定是哪个线程or进程
先访问这些资源,这就可以出现问题,特别是对于临界区资源,只能
要求同时只有一个进程or线程访问的。所以我们只要解决了对于临界区的
访问就是解决了线程是否安全的问题。我是这样认为的。为了解决这个
同步问题,主要还是互斥量的使用。

互斥量

互斥量是这样一把锁,在访问共享资源之前,对互斥量进行设置(加锁)
访问结束之后,再对互斥量进行设置(解锁)。对互斥量加锁之后,任何其他
试图再去对互斥量加锁的线程就会被阻塞,知道当前线程释放互斥量。我觉得
这跟设置一个 int block 变量一样,初始的时候blokc = 1;加锁则-1 block=0
解锁则+1,;每次加锁之前判断block是否为1,为1 则加锁,否则阻塞。当检测
到block = 1 时,给所有唤醒等待的线程。

 #include <pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex,                        const pthread_mutexattr_t *restrict attr); int pthread_mutex_destory(pthread_mutex_t *mutex);                 俩个函数的返回值:若成功,返回0;否则,返回错误编号 attr是互斥量的属性, NULL表示使用的默认属性,具体可以查看文档 /* 调用malloc分配内存的锁 需要使用pthread_mutex_init函数初始化,释放内存前需要使用  pthread_mutex_destory 函数先销毁 */ int pthread_mutex_lock(pthread_mutex_t *mutex); /* 加锁 */ int pthread_mutex_trylock(pthread_mutex_t *mutex); /* 加锁,加锁失败返回错误但是不会阻塞 */ int pthread_mutex_unlock(pthread_mutex_t *mutex); /* 解锁 */                返回值:若成功,返回0;否则,返回错误编号 int pthread_mutex_timelock(pthread_mutex_t *restrict mutex,                             const struct timespec *restrict tsptr);  /* 加锁,在规定的时间内不能获得锁就自动返回,不无限阻塞 */

读写锁

我觉得大家肯定还记得经典的读写者问题,当然了还有相应的生产者和消费者问题,这个

读写锁就是读写者问题。当已经加上写锁的时候,再加读锁和写锁都会被阻塞。当已经加上读锁
的时候,还可以继续加读锁,但是加写锁会被阻塞。这就是为了保证内容的一致性。

    初始化和销毁一个读写锁,通上面的互斥量锁一样    #include <pthread.h>    int pthread_rwlock_init(pthread_rwlock *restrict rwlock,                            const pthread_rwlockattr_t *restrict sttr);    int pthread_rwlock_destoru(pthred_rwlock *rwlock);                        俩个函数:若成功,返回0;否则返回失败码    /* 加解锁 */    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); /* 加读锁 */    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); /* 加写锁 */    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); /* 解读/写锁 */                   返回值:若成功,返回0;否则,返回错误编号    /* 加带有不阻塞的锁 */    int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); /* 加读锁,加锁失败返回错误但是不会阻塞 */    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); /* 加写锁,加锁失败返回错误但是不会阻塞 */                   返回值:若成功,返回0;否则,返回错误编号    /* 加带有超时的锁 */    int pthread_rwlock_timerdlock(pthread_rwlock_t *restrict rwlock,                                const struct timespec *restrict tsptr);     int pthread_rwlock_timewrlock(pthread_rwlock_t *restrict rwlock,                                const struct timespec *restrict tsptr);                    返回值:若成功,返回0;否则,返回错误编号    /* 加锁,在规定的时间内不能获得锁就自动返回,不无限阻塞 */

条件锁

当你需要达到一定的条件,才继续运行时,这个就是你需要的锁了
    /* 初始化和销毁一个条件锁,通上面的互斥量锁一样 */    #include <pthread.h>    int pthread_cond_init(pthread_cond *restrict cond,                            const pthread_condattr_t *restrict sttr);    int pthread_cond_destoru(pthred_cond *cond);                        俩个函数:若成功,返回0;否则返回失败码    /* 加锁 */    int pthread_cond_wait(pthread_cond_t *restrict cond,                          pthread_mutex_t *restrict mutex);                    返回值:若成功,返回0;否则,返回错误编号    /* 加带有超时的锁 */    int pthread_cond_timewait(pthread_cond_t *restrict cond,                               pthread_mutex_t *restrict mutex);                               const struct timespec *restrict tsptr);                    返回值:若成功,返回0;否则,返回错误编号    /* 加锁,在规定的时间内不能获得锁就自动返回,不无限阻塞        条件锁的mutex参数,是已经加过锁的互斥量,这样做关闭了条件检查       和线程进入休眠状态等待条件改变这俩个操作之间的时间通道。       保证线程不会错过条件的任何变化。因为条件的状态的改变也需要用到       同一个互斥量锁,把该线程放到条件等待队列之后,就解锁互斥量       函数返回时 重新加锁互斥量 */   /* 解锁 */   int pthread_cond_signal(pthread_cond_t *cond);   int pthread_cond_broadcast(pthread_cond_t *cond);                   俩个函数返回值:若成功,返回0;否则,返回错误编号   互斥量加锁锁之后 改变条件状态 解锁 之后才能 发送信号 通知等待线程

自旋锁

互斥量锁,在没有资源的时候,是直接阻塞,自旋锁不通过休眠使线程阻塞
而是在获取锁之前一直处于盲等(自旋转),自选锁主要用于一下情况:锁被持有
的时间段,而且线程不希望在重新调度上花费太多成本。因为自旋锁盲等,我认为
是直接while(true) ,所以会在等待期间会一直占用cpu资源,所以适合短锁。

    初始化和销毁一个自旋锁,通上面的互斥量锁一样    #include <pthread.h>    int pthread_spin_init(pthread_spin *restrict spin,                            const pthread_spinattr_t *restrict sttr);    int pthread_spin_destory(pthred_spin *spin);                        俩个函数:若成功,返回0;否则返回失败码    /* 加解锁 */    int pthread_spin_lock(pthread_spin_t *spin); /* 加锁 */    int pthread_spin_trylock(pthread_spin_t *spin); /* 加锁 */    int pthread_spin_unlock(pthread_spin_t *spin); /* 解读/写锁 */                   返回值:若成功,返回0;否则,返回错误编号    /* 加带有不阻塞的锁 */    int pthread_spin_tryrdlock(pthread_spin_t *spin); /* 加读锁,加锁失败返回错误但是不会阻塞 */    int pthread_spin_trywrlock(pthread_spin_t *spin); /* 加写锁,加锁失败返回错误但是不会阻塞 */                   返回值:若成功,返回0;否则,返回错误编号

屏障

等待到一定数量的线程都调用 pthread_barrier_wait 之后唤醒所有因为调用pthread_barrier_wait 休眠的线程。
    初始化和销毁一个屏障    #include <pthread.h>    int pthread_barrier_init(pthread_barrier *restrict barrier,                            const pthread_barrierattr_t *restrict sttr,                             unsigned int count);    int pthread_barrier_destory(pthred_barrier *barrier);                        俩个函数:若成功,返回0;否则返回失败码    int pthread_barrier_wait(pthread_barrier_t *barrier);                    返回值:若成功,返回0;否则,返回错误编号    调用pthread_barrier_wait 的线程在屏障技术为满足条件时,会进入    休眠。如果该线程是最后一个调用pthread_barrier_wait的线程,满    足了屏障技术,所有的线程被唤醒。
0 0