Linux线程同步

Linux下提供了多种方式来处理线程同步,最常用的是互斥锁、条件变量和信号量。

Linux线程同步-----互斥锁(Mutex)

互斥锁(Mutex)

与信号处理函数一样,线程在访问全局资源时也会遇到非原子操作导致的冲突(可重入问题). 比如两个线程要对同一个寄存器加1, 并行访问时可能会导致只加了一次.
不可重入操作的特点时,输出不仅依赖于输入,还依赖于状态, 比如加1 依赖于状态,这个状态是寄存器原值. 访问状态和修改状态不是原子操作的话,就会导致并发冲突

  1. 初始化锁
    int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr);
    其中参数 mutexattr 用于指定锁的属性(见下),如果为NULL则使用缺省属性。
    互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。当前有四个值可供选择:
    (1)PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
    (2)PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
    (3)PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。
    (4)PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。

  2. 阻塞加锁
    int pthread_mutex_lock(pthread_mutex *mutex);

  3. 非阻塞加锁
    int pthread_mutex_trylock( pthread_mutex_t *mutex);
    该函数语义与 pthread_mutex_lock() 类似,不同的是在锁已经被占据时返回 EBUSY 而不是挂起等待。

  4. 解锁(要求锁是lock状态,并且由加锁线程解锁)
    int pthread_mutex_unlock(pthread_mutex *mutex);

  5. 销毁锁(此时锁必需unlock状态,否则返回EBUSY)
    int pthread_mutex_destroy(pthread_mutex *mutex);

Linux线程同步条件变量(cond)

条件变量是利用线程间共享全局变量进行同步的一种机制。条件变量上的基本操作有:触发条件(当条件变为 true 时);等待条件,挂起线程直到其他线程触发条件。

  1. 初始化条件变量
    int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);
    尽管POSIX标准中为条件变量定义了属性,但在Linux中没有实现,因此cond_attr值通常为NULL,且被忽略。

  2. 有两个等待函数
    (1)无条件等待
    int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
    (2)计时等待
    int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
    如果在给定时刻前条件没有满足,则返回ETIMEOUT,结束等待,其中abstime以与time()系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。
     
    无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求(用 pthread_cond_wait() 或 pthread_cond_timedwait() 请求)竞争条件(Race Condition)。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。

  3. 激发条件
    (1)激活一个等待该条件的线程(存在多个等待线程时按入队顺序激活其中一个)  
    int pthread_cond_signal(pthread_cond_t *cond);
    (2)激活所有等待线程
    int pthread_cond_broadcast(pthread_cond_t *cond);

  4. 销毁条件变量
    int pthread_cond_destroy(pthread_cond_t *cond);
    只有在没有线程在该条件变量上等待的时候才能销毁这个条件变量,否则返回EBUSY

说明:

1.pthread_cond_wait自动解锁互斥量(如同执行了pthread_unlock_mutex),并等待条件变量触发。这时线程挂起,不占用CPU时间,直到条件变量被触发(变量为ture)。在调用 pthread_cond_wait之前,应用程序必须加锁互斥量。pthread_cond_wait函数返回前,自动重新对互斥量加锁(如同执行了pthread_lock_mutex)。

2. 互斥量的解锁和在条件变量上挂起都是自动进行的。因此,在条件变量被触发前,如果所有的线程都要对互斥量加锁,这种机制可保证在线程加锁互斥量和进入等待条件变量期间,条件变量不被触发。条件变量要和互斥量相联结,以避免出现条件竞争——个线程预备等待一个条件变量,当它在真正进入等待之前,另一个线程恰好触发了该条件(条件满足信号有可能在测试条件和调用pthread_cond_wait函数(block)之间被发出,从而造成无限制的等待)。

3. 条件变量函数不是异步信号安全的,不应当在信号处理程序中进行调用。特别要注意,如果在信号处理程序中调用 pthread_cond_signalpthread_cond_boardcast函数,可能导致调用线程死锁

Linux线程同步----- 信号量

如同进程一样,线程也可以通过信号量来实现通信,虽然是轻量级的。
线程使用的基本信号量函数有四个:

  1. 初始化信号量
    int sem_init (sem_t *sem , int pshared, unsigned int value);
  • 参数:
    sem - 指定要初始化的信号量;
    pshared - 信号量 sem 的共享选项,linux只支持0,表示它是当前进程的局部信号量;
    value - 信号量 sem 的初始值。
  1. 信号量值加1
    给参数sem指定的信号量值加1。
    int sem_post(sem_t *sem);

  2. 信号量值减1
    给参数sem指定的信号量值减1。
    int sem_wait(sem_t *sem);
    如果sem所指的信号量的数值为0,函数将会等待直到有其它线程使它不再是0为止。

  3. 销毁信号量
    销毁指定的信号量。
    int sem_destroy(sem_t *sem);

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

推荐阅读更多精彩内容

  • linux线程同步 信号灯:与互斥锁和条件变量的主要不同在于"灯"的概念,灯亮则意味着资源可用,灯灭则意味着不可用...
    鲍陈飞阅读 679评论 0 2
  • 多线程系列文章源码头文件内容: #include #include #include 作为程序员,就是要减少重复劳...
    batbattle阅读 903评论 0 1
  • 线程基础 线程是进程的一个执行单元,执行一段程序片段,线程共享全局变量;线程的查看可以使用命令或者文件来进行查看;...
    秋风弄影阅读 730评论 0 0
  • Q:为什么出现多线程? A:为了实现同时干多件事的需求(并发),同时进行着下载和页面UI刷新。对于处理器,为每个线...
    幸福相依阅读 1,565评论 0 2
  • 转自:Youtherhttps://www.cnblogs.com/youtherhome/archive/201...
    njukay阅读 1,601评论 0 52