关于多线程中的几把锁

2019-07-04 11:22:02 浏览数 (1)


之前lz说后续会继续做SQLite的操作,在lz做版本swift版本操作SQLite过程中遇到了多线程访问的问题,今天就给大家梳理一下其中对共享数据多线程操作中的?,或者是iOS开发中的几种?甚至这些锁很多实用IT开发中……

1 自旋锁

何谓自旋锁?它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。

说白了自旋锁锁有两个功能:1 共享资源加锁 2 共享资源被其他加锁,则原地等待不停查询

代码语言:javascript复制
func spinLock(){
    /**
     自旋锁
     lock/unlock要成对出现
     **/
    var ossLock = os_unfair_lock_s.init(_os_unfair_lock_opaque: UInt32(OS_SPINLOCK_INIT))
    //    var number = 0
    for i in 0..<100 {
        DispatchQueue.global().async {
            os_unfair_lock_lock(&ossLock)
            //            os_unfair_lock_trylock(&ossLock)
            //            os_unfair_lock_unlock(&ossLock)
            number = number 1
            print(number,"t",i, "spinLock")
            os_unfair_lock_unlock(&ossLock)
        }
    }
}

2 信号量?

信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号量。

说起信号量有一个很直观有趣的故事:

以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。

代码语言:javascript复制
func semaphore(){
    let  signalCount = 1
    let semaphore = DispatchSemaphore(value: signalCount)
    
    let timeout : DispatchTime = DispatchTime.init(uptimeNanoseconds: NSEC_PER_SEC * UInt64(signalCount))
    for i in 0...200 {
        //        queue.async(execute: DispatchWorkItem.init(block: {
        //            semaphore.wait(timeout: timeout)
        //            number = number   1
        //            print(number, "t", i, "semaphore")
        //            semaphore.signal()
        //        }));
        DispatchQueue.global().async {
            let result = semaphore.wait(timeout: timeout)
            switch result {
            case .success:
                number = number   1
                print(number, "t", i, "semaphore")
                break
            default:
                print(number, "t", i, "等待失败semaphore")
                
            }
            semaphore.signal()
        }
    }
    
}

3 pthread_mutex_t(p锁)

p锁是Linux平台的锁,在此我们不多介绍,直接上代码

代码语言:javascript复制
func pthreadMutex(){
    
    var mutex : pthread_mutex_t =  pthread_mutex_t()
    var attr:Optional<pthread_mutexattr_t> = nil
    
    //进行初始化可以添加附加属性
    attr = pthread_mutexattr_t()
    
    if attr == nil {
        pthread_mutex_init(&mutex, nil) //此时如果用于递归中则会形成死锁
        
        
        DispatchQueue.global().async {
            pthread_mutex_lock(&mutex)
            number = number   1
            print(number,"111")
            pthread_mutex_unlock(&mutex)
        }
        DispatchQueue.global().async {
            pthread_mutex_lock(&mutex)
            number = number   1
            print(number,"222")
            pthread_mutex_unlock(&mutex)
        }
        
        
    }else{
        pthread_mutexattr_init(&attr!)
        pthread_mutexattr_settype(&attr!, PTHREAD_MUTEX_RECURSIVE)
        pthread_mutex_init(&mutex,  &attr!)
        
        var value = 5
        DispatchQueue.global().async {
            
            func test(_ v: Int) ->Void{
                pthread_mutex_lock(&mutex)
                if v > 0 {
                    print("value= ",v)
                    test(v-1)
                }
                pthread_mutex_unlock(&mutex)
            }       
            test(value)
        }
    }   
}

p锁是众多锁中很少能订制的一把锁,从上栗中我们看到即可用于互斥也能进行配置达到递归锁的目的,大家可以试试,在默认情况下欲行递归是否形成死锁…

4 condtion

这个不多多说,想加锁解锁需要满足条件才可以,咱们直接上代码

代码语言:javascript复制
func condtion(){
    
    let  condtion = NSConditionLock.init(condition: 0) //尝试加锁会从whenCondition:0的位置开始
    var p = 100
    DispatchQueue.global().async {
        condtion.lock(whenCondition: 1)
        print("finished")
        condtion.unlock(withCondition: p)
    }
    
    DispatchQueue.global().async {
        condtion.lock(whenCondition: 0)
        p = 1
        print("start")
        condtion.unlock(withCondition: p)
    }
}

0 人点赞