unix线程同步

线程同步

因为线程共享进程的存储空间,所以进程的栈 全局变量都可以被
线程所访问,但是又因为竞度问题,我们无法判定是哪个线程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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值