线程同步与互斥

01 概述

    线程同步,是协调步调,按预定先后次序执行,解决与时间相关的错误。

    线程不同步,产生的现象就是数据混乱:

    1、资源共享(系统层面)

    2、调度随机(系统层面)

    3、缺乏必要的同步机制(用户层面,我们可以在这里做限制)

    多个控制流访问同一共享资源时,必须同步。

02 互斥锁

2.1 概述

    当多个线程并发的访问同一个共享资源的时候,可能导致数据异常。可以通过互斥锁确保一个共享资源每次只能被一个线程访问。

    互斥锁属于重量级锁,因为存在用户态和内核态的切换。

2.2 操作

    1、初始化

    静态初始化:

    pthread_mutex_t mutex = PTHREAD_MUTEX_INITILIZER;

    动态初始化:

    int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);

    int pthread_mutex_destroy(pthread_mutex_t *mutex);

    2、pthread_mutex_lock

    阻塞加锁。

    3、pthread_mutex_trylock

    非阻塞加锁。

    4、pthread_mutex_timelock

    5、pthread_mutex_unlock

    解锁,同时会将阻塞在该锁上的所有线程全部唤醒。

    6、pthread_mutex_destroy

2.3 死锁

    产生原因:

    1、对同一互斥量重复加锁;

    2、持有锁A的线程1请求锁B,持有锁B的线程请求锁A。

    避免方法:

    1、保证资源的获取顺序,要求每个线程获取资源的顺序一致;

    2、当得不到所有所需要的资源时,放弃已经获得的资源,等待。

03 读写锁

3.1 概述

    pthread读写锁把对共享资源的访问者分为读者和写者,读者只对共享资源进行读访问,写者只对共享资源进行写操作。在互斥机制,读者和写者都需要独立独占互斥量以独占共享资源,在读写锁机制下,允许同时有多个读者访问共享资源,只有写者才需要独占资源(读共享,写独占)。

    相比互斥锁,读写机制由于允许多个读者同时访问共享资源,进一步提高了多线程的并发度。

3.2 记录上锁

    记录上锁是读写锁的一种拓展(进程间的锁),可以用于有亲缘关系或者无亲缘关系的进程之间共享某个文件的读写。被锁住的文件通过其文件描述符访问,执行上锁操作的函数是fcntl,这种类型的锁通常在内核中维护,其属主是由属主的进程ID标识的。    

    这意味着这些锁用于不同进程间的上锁,而不是用于同一进程内不同线程的上锁。

3.3 操作

    1、初始化

    pthread_rwlock_init

    2、pthread_ rwlock _lock

    3、pthread_ rwlock _timelock

    4、pthread_ rwlock _rdlock

    5、pthread_ rwlock _wrlock

    6、pthread_ rwlock _unlock

    7、pthread_ rwlock _destroy

3.4 使用

    适用于读操作远大于写操作的场景。

04 条件变量

 4.1 概述

    条件锁就是所谓的条件变量,某一个线程因为某个条件未满足时可以使用条件变量使该程序处于阻塞状态(主要用于访问公共资源)。一旦条件满足以“信号量”的方式唤醒一个因为条件而被阻塞的线程。

    最为常见的就是在线程池中,起初没有任何时刻任务队列为空,此时线程池中的线程以为“任务队列为空”这个条件处于阻塞状态。一旦有任务进来,就会以信号量的方式唤醒一个线程来处理这个任务。这个过程中就使用到了条件变量pthread_cond_t。

    与互斥锁相比较,互斥锁用于上锁,条件变量(条件锁)用于等待。

    与读写锁相比较,更加先进,因为可以使用条件变量判断这个共享区域是否存在数据是否可以访问,不需要读写锁再去判断了,减少不必要的竞争。

    条件变量的特性:

    1、条件变量不是锁;

    2、可以造成线程阻塞;

    3、与mutex配合使用。

 4.2 操作

    1、初始化:  

    静态初始化:pthread_cond_t condition = PTHREAD_COND_INITILIZER;

    动态初始化:pthread_cond_init

    2、pthread_cond_destroy

    3、pthread_cond_wait

    其语义相当于:首先解锁互斥锁,然后以阻塞方式等待条件变量的信号,收到信号后又会对互斥锁加锁。

    为了防止“虚假唤醒”,该函数一般放在while循环体中。

    while(当前线程中条件不成立){

        pthread_cond_wait(cond, mutex);

        //解锁,其他线程使条件成立发送信号,加锁

    }

    4、pthread_cond_unlock

    释放互斥锁

    5、pthread_cond_timedwait

    以阻塞方式等待,如果时间到了条件还没有满足还是会结束。

   6、pthread_cond_broadcast

    唤醒全部阻塞在条件变量上的线程(一般不推荐使用,使用pthread_cond_signal)。

    7、pthread_cond_signal

    在另一个线程中改变线程,条件满足发送信号。唤醒一个等待的线程(可能有多个线程处于阻塞状态),唤醒哪个线程由具体的线程调度策略决定。

05 文件加锁

5.1 概述

    应用程序经常需要读取文件中的数据,修改数据,然后回写数据,如果某一时刻只有一个进程执行文件操作不存在任何问题,但是如果同时多个进程执行操作就会出现问题。这就需要多进程之间实现同步,可以使用信号量来完成所需的同步,但通常文件锁更好一些,因为内核能够将锁和文件关联起来。

5.2 操作

    1、flock

    flock[file lock],建议性锁,不具备强制性。一个进程使用flock将文件锁住,另一个进程可以直接操作正在被锁的文件,修改文件中的数据。

    flock系统调用是在整个文件中加锁,通过对传入的fd所指向的文件进行操作,然后再通过operation参数所设置的值来确定做什么样的操作,operation的值如下:

    在默认情况下,如果另外一个进程已经持有了文件上的一个不兼容的锁,那么flock会阻塞。如果需要防止这种情况的出现,可以在operation参数中对这些值取OR(|)操作。在这种情况下,如果一个进程已经有了一个文件上的一个不兼容锁,那么flock就会阻塞。相反,它会返回-1,并将errno设置成EWOULDBLOCK。

    flock放置的锁有如下限制:

    1、粗粒度,只能对整个文件进行加锁;

    2、通过flock只能放置劝告式锁。

    3、很多NFS实现不识别flock放置的锁。

    2、fcntl

    原型:int flock(int fd, int operation);

    fcntl函数覆盖了flock的功能,且提供了比flock更加强大的功能,但是在某些应用中仍然使用flock函数,并且在继承和释放锁方面的一些语义中flock与fcntl还是有所不同的。

    3、ftruncate

    原型:int ftruncate(int fd, off_t length);

    功能:改变文件大小

    说明:ftruncate会将参数fd指定的文件大小改为参数length指定的大小。如果原来的文件大小比参数length大,则超过的部分被删除。

06 信号量

    信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。

    从信号量的描述来看,其功能类似互斥锁,但是二者存在诸多区别:

    1、互斥量用于线程间互斥,信号量用于线程间同步(本质区别);

    2、互斥量值只能为0/1,信号量值可以为非负整数;

    3、互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容