百度
360搜索
搜狗搜索

mutex,深入理解mutex工作机制详细介绍

本文目录一览: mutex=1表示什么意思

mutex为互斥信号量,其初值为1,取值范围为(-1, 0, 1)。 当mutex=1时,表示两个进程皆未进入需要互斥的临界区;当mutex=0时,表示有一个进程进入临界区运行,另外-一个必须等待,挂入阻塞队列;当mutex=-1时,表示有一个进程正在临界区运行,另外一个进程因等待而阻塞在信号量队列中,需要被当前已在临界区运行的进程退出时唤醒。

深入理解mutex工作机制

可以认为是一种更加轻量级的latch, 两者的区别在于:mutex是内存结构本身所包含,随着内存的分配而分配、销毁而销毁,latch是一种独立的内存结构。基于这个特性,mutex保护的内存结构更细粒度,并发性、支持性要好于latch.
与shared latch一样可使mutex用cas模式申请latch. 因此也可以把mutex当成一种shared latch, 只是其粒度更细,更加轻量级。mutex采用spin+FIRO策略,而shared latch采用spin+FIFO策略。更多详细关于mutex的原理可以参见:
从10.2.0.2版本开始,oracle的mutex机制逐步替代了传统的library cache的一些机制。
#### 10.2.0.5 ####
#### 11.2.0.4 ####
不同版本中,对于library cache的latch变化较大,特别是从Oracle 10gR2(10.2.0.2)开始,引入了mutex来替代cursor的latch. 在该版本上通过隐含参数_kks_use_mutex_pin的调整可以限制是否使用Mutex机制来实现Cursor Pin.
mutex与latch的对应关系如下:
以下参数在11.2.0.2以上才有
由于mutex采用了传统的spin+sleep机制而不是latch的spin+post机制,所以sleep time的设置对于mutex性能具有重要地位,一般来说由于mutex的冲突远比latch要小,所以合适的yield和更小的sleep选择是恰当的。一般情况不需要改动,默认都是1ms.
不同模式的比较可以参考:
不包含sleep, 只在简单yield之后进行不断的mutex spin. 显然,在冲突不发生的情况下会有最好的性能,但是在有冲突的时候可能会消耗很高的CPU资源。
对10g模式的一种修正,增加了sleep部分以降低CPU消耗,sleep时间收到参数_first_spare_parameter的控制
在Solaris SPARC 10.2.0.4这个参数是_second_spare_parameter.
mutex的spin次数受mutex_spin_count控制,默认为255. 该参数可以动态修改。
某些时候,该值可能需要适当增大来获取更好的性能。设置方法可参考latch的spin count设置方法。v$mutex_sleep_history视图包含相关的gets和sleep信息。
关于mutex_spin_conut设置对mutex响应性能的影响可参考:

[RT-Thread]互斥锁(mutex)

和 semaphore 一样, mutex 在RTT中也归类为 ipc ( ipc 应该是进程间通信,感觉命名是不是有点不贴切)。
mutex 用于资源互斥的场景,比如多个线程可能同时访问(R/W)同一个全局变量,这个时候,就需要加锁控制。

仍然主要关注 mutex控制块 、 take 和 release 操作。

parent :
和其它 ipc 方式相同,主要是维护 suspend_thread 。
value :
value其实就两个值:0或者1,1表示已被持有,0表示空闲状态。
original_priority :
保存持有该mutex的thread的本来的线程优先级,便于优先级继承后,恢复原本线程优先级。
hold :
hold 记录被同一thread请求的次数,嵌套场景。
owner :
持有该mutex的thread。

linux线程同步的互斥锁(mutex)到底怎么用的》?谢谢

互斥锁(mutex) 通过锁机制实现线程间的同步。
1、初始化锁。在Linux下,线程的互斥量数据类型是pthread_mutex_t。在使用前,要对它进行初始化。
2、静态分配:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
3、动态分配:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
4、加锁。对共享资源的访问,要对互斥量进行加锁,如果互斥量已经上了锁,调用线程会阻塞,直到互斥量被解锁。
int pthread_mutex_lock(pthread_mutex *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); 解锁。在完成了对共享资源的访问后,要对互斥量进行解锁。 int pthread_mutex_unlock(pthread_mutex_t *mutex); 销毁锁。锁在是使用完成后,需要进行销毁以释放资源。 int pthread_mutex_destroy(pthread_mutex *mutex); #include

#include

#include

#include

#include "iostream" using namespace std; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int tmp; void* thread(void *arg) { cout << "thread id is " << pthread_self() << endl; pthread_mutex_lock(&mutex); tmp = 12; cout << "Now a is " << tmp << endl; pthread_mutex_unlock(&mutex); return NULL; } int main() { pthread_t id; cout << "main thread id is " << pthread_self() << endl; tmp = 3; cout << "In main func tmp = " << tmp << endl; if (!pthread_create(&id, NULL, thread, NULL)) { cout << "Create thread success!" << endl; } else { cout << "Create thread failed!" << endl; } pthread_join(id, NULL); pthread_mutex_destroy(&mutex); return 0; } //编译:g++ -o thread testthread.cpp -lpthread

mutex的英文音标是什么,怎么发音? 怎么发音呢?

mutex
互斥(体)
/mjuteks/

信号量vs互斥锁(Semaphore vs Mutex)

信号量是一个被线程共享的非负变量。信号量是一个发信号的机制。一个等待一个信号量的线程可以被其他线程通知(signal)。这个机制通过 wait 和 signal 两个原子操作(atomic operations)来实现进程同步。

一个信号量要么允许访问资源,要么不允许访问资源。二者只能选其一。而具体是哪一种,则要看设置。

详情可参考《 信号量:二进位信号量和计数信号量 》这篇文章。

互斥锁其实是一个对象。Mutex的全称是Mutual Exclusion Object,也就是互斥锁是一个互斥对象。它是一种特殊的二进位信号量(binary semaphore),用来控制访问共享区域资源。它包括一个优先级继承机制,以避免扩展的优先级反转问题。它允许当前优先级较高的任务在阻塞状态下维持的时间尽可能的少。然而,优先级继承并不能完全避免优先级反转,而只会最小化其影响。

对于单个缓冲区(single buffer),我们可以将4kb缓冲区分成四个1kb缓冲区。信号量可以与这四个缓冲区相关联。这允许用户和生产者同时处理不同的缓冲区。

互斥锁用于提供互斥,它使得拥有钥匙(key or mutex)的生产者才能访问资源。只要生产者占用了缓冲区(buffer),用户必须等待,反之亦然。在互斥锁的机制中,整块缓冲区始终只能提供给一个线程访问。

下面列举信号量的优点:

下面列举互斥锁的优点:

下面列举信号量的缺点:

下面列举互斥锁的缺点:

Linux 之mutex 源码分析

?mutex相关的函数并不是linux kernel实现的,而是glibc实现的,源码位于nptl目录下。

http://ftp.gnu.org/pub/gnu/glibc/glibc-2.3.5.tar.gz

首先说数据结构:

typedef union

{

? struct

? {

??? int __lock;

??? unsigned int __count;

??? int __owner;

??? unsigned int __nusers;

??? /* KIND must stay at this position in the structure to maintain

?????? binary compatibility.? */

??? int __kind;

??? int __spins;

? } __data;

? char __size[__SIZEOF_PTHREAD_MUTEX_T];

? long int __align;

} pthread_mutex_t;

?int __lock;? 资源竞争引用计数

?int __kind; 锁类型,init 函数中mutexattr 参数传递,该参数可以为NULL,一般为 PTHREAD_MUTEX_NORMAL

结构体其他元素暂时不了解,以后更新。

/*nptl/pthread_mutex_init.c*/

int

__pthread_mutex_init (mutex, mutexattr)

???? pthread_mutex_t *mutex;

???? const pthread_mutexattr_t *mutexattr;

{

? const struct pthread_mutexattr *imutexattr;

? assert (sizeof (pthread_mutex_t) <= __SIZEOF_PTHREAD_MUTEX_T);

阅读更多 >>>  苹果12怎么看内存

? imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr;

? /* Clear the whole variable.? */

? memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T);

? /* Copy the values from the attribute.? */

? mutex->__data.__kind = imutexattr->mutexkind & ~0x80000000;

? /* Default values: mutex not used yet.? */

? // mutex->__count = 0;????????already done by memset

? // mutex->__owner = 0;????????already done by memset

? // mutex->__nusers = 0;????????already done by memset

? // mutex->__spins = 0;????????already done by memset

? return 0;

}

init函数就比较简单了,将mutex结构体清零,设置结构体中__kind属性。

/*nptl/pthread_mutex_lock.c*/

int

__pthread_mutex_lock (mutex)

???? pthread_mutex_t *mutex;

{

? assert (sizeof (mutex->__size) >= sizeof (mutex->__data));

? pid_t id = THREAD_GETMEM (THREAD_SELF, tid);

? switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))

??? {

???? …

??? default:

????? /* Correct code cannot set any other type.? */

??? case PTHREAD_MUTEX_TIMED_NP:

??? simple:

????? /* Normal mutex.? */

????? LLL_MUTEX_LOCK (mutex->__data.__lock);

????? break;

??…

??}

? /* Record the ownership.? */

? assert (mutex->__data.__owner == 0);

? mutex->__data.__owner = id;

#ifndef NO_INCR

? ++mutex->__data.__nusers;

#endif

? return 0;

}

该函数主要是调用LLL_MUTEX_LOCK, 省略部分为根据mutex结构体__kind属性不同值做些处理。

宏定义函数LLL_MUTEX_LOCK最终调用,将结构体mutex的__lock属性作为参数传递进来

#define __lll_mutex_lock(futex)????????????????????????????????????????????????\

? ((void) ({????????????????????????????????????????????????????????????????\

??? int *__futex = (futex);????????????????????????????????????????????????\

??? if (atomic_compare_and_exchange_bool_acq (__futex, 1, 0) != 0)????????\

????? __lll_lock_wait (__futex);????????????????????????????????????????\

? }))

atomic_compare_and_exchange_bool_acq (__futex, 1, 0)宏定义为:

#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \

? ({ __typeof (mem) __gmemp = (mem);????????????????????????????????????? \

???? __typeof (*mem) __gnewval = (newval);????????????????????????????? \

????? \

???? *__gmemp == (oldval) ? (*__gmemp = __gnewval, 0) : 1; })

这个宏实现的功能是:

如果mem的值等于oldval,则把newval赋值给mem,放回0,否则不做任何处理,返回1.

由此可以看出,当mutex锁限制的资源没有竞争时,__lock 属性被置为1,并返回0,不会调用__lll_lock_wait (__futex); 当存在竞争时,再次调用lock函数,该宏不做任何处理,返回1,调用__lll_lock_wait (__futex);

void

__lll_lock_wait (int *futex)

{

? do

??? {

????? int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1);

????? if (oldval != 0)

lll_futex_wait (futex, 2);

??? }

? while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0);

}

atomic_compare_and_exchange_val_acq (futex, 2, 1); 宏定义:

/* The only basic operation needed is compare and exchange.? */

#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \

? ({ __typeof (mem) __gmemp = (mem);????????????????????????????????????? \

???? __typeof (*mem) __gret = *__gmemp;????????????????????????????????????? \

???? __typeof (*mem) __gnewval = (newval);????????????????????????????? \

????? \

???? if (__gret == (oldval))????????????????????????????????????????????? \

?????? *__gmemp = __gnewval;????????????????????????????????????????????? \

???? __gret; })

这个宏实现的功能是,当mem等于oldval时,将mem置为newval,始终返回mem原始值。

此时,futex等于1,futex将被置为2,并且返回1. 进而调用

lll_futex_wait (futex, 2);

#define lll_futex_timed_wait(ftx, val, timespec)????????????????????????\

({????????????????????????????????????????????????????????????????????????\

?? DO_INLINE_SYSCALL(futex, 4, (long) (ftx), FUTEX_WAIT, (int) (val),????????\

???? (long) (timespec));????????????????????????????????\

?? _r10 == -1 ? -_retval : _retval;????????????????????????????????????????\

})

该宏对于不同的平台架构会用不同的实现,采用汇编语言实现系统调用。不过确定的是调用了Linux kernel的futex系统调用。

futex在linux kernel的实现位于:kernel/futex.c

SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,

struct timespec __user *, utime, u32 __user *, uaddr2,

阅读更多 >>>  苹果手机的内存在哪里看

u32, val3)

{

struct timespec ts;

ktime_t t, *tp = NULL;

u32 val2 = 0;

int cmd = op & FUTEX_CMD_MASK;

if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||

????? cmd == FUTEX_WAIT_BITSET ||

????? cmd == FUTEX_WAIT_REQUEUE_PI)) {

if (copy_from_user(&ts, utime, sizeof(ts)) != 0)

return -EFAULT;

if (!timespec_valid(&ts))

return -EINVAL;

t = timespec_to_ktime(ts);

if (cmd == FUTEX_WAIT)

t = ktime_add_safe(ktime_get(), t);

tp = &t;

}

/*

?* requeue parameter in 'utime' if cmd == FUTEX_*_REQUEUE_*.

?* number of waiters to wake in 'utime' if cmd == FUTEX_WAKE_OP.

?*/

if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||

??? cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)

val2 = (u32) (unsigned long) utime;

return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);

}

futex具有六个形参,pthread_mutex_lock最终只关注了前四个。futex函数对参数进行判断和转化之后,直接调用do_futex。

long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,

u32 __user *uaddr2, u32 val2, u32 val3)

{

int clockrt, ret = -ENOSYS;

int cmd = op & FUTEX_CMD_MASK;

int fshared = 0;

if (!(op & FUTEX_PRIVATE_FLAG))

fshared = 1;

clockrt = op & FUTEX_CLOCK_REALTIME;

if (clockrt && cmd != FUTEX_WAIT_BITSET && cmd != FUTEX_WAIT_REQUEUE_PI)

return -ENOSYS;

switch (cmd) {

case FUTEX_WAIT:

val3 = FUTEX_BITSET_MATCH_ANY;

case FUTEX_WAIT_BITSET:

ret = futex_wait(uaddr, fshared, val, timeout, val3, clockrt);

break;

???????? …

default:

ret = -ENOSYS;

}

return ret;

}

省略部分为对其他cmd的处理,pthread_mutex_lock函数最终传入的cmd参数为FUTEX_WAIT,所以在此只关注此分之,分析futex_wait函数的实现。

static int futex_wait(u32 __user *uaddr, int fshared,

????? u32 val, ktime_t *abs_time, u32 bitset, int clockrt)

{

struct hrtimer_sleeper timeout, *to = NULL;

struct restart_block *restart;

struct futex_hash_bucket *hb;

struct futex_q q;

int ret;

?????????? … … //delete parameters check and convertion

retry:

/* Prepare to wait on uaddr. */

ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);

if (ret)

goto out;

/* queue_me and wait for wakeup, timeout, or a signal. */

futex_wait_queue_me(hb, &q, to);

… … //other handlers

return ret;

}

futex_wait_setup 将线程放进休眠队列中,

futex_wait_queue_me(hb, &q, to);将本线程休眠,等待唤醒。

唤醒后,__lll_lock_wait函数中的while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); 语句将被执行,由于此时futex在pthread_mutex_unlock中置为0,所以atomic_compare_and_exchange_bool_acq (futex, 2, 0)语句将futex置为2,返回0. 退出循环,访问用户控件的临界资源。

/*nptl/pthread_mutex_unlock.c*/

int

internal_function attribute_hidden

__pthread_mutex_unlock_usercnt (mutex, decr)

???? pthread_mutex_t *mutex;

???? int decr;

{

? switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))

??? {

???… …

??? default:

????? /* Correct code cannot set any other type.? */

??? case PTHREAD_MUTEX_TIMED_NP:

??? case PTHREAD_MUTEX_ADAPTIVE_NP:

阅读更多 >>>  b460m支持多大内存频率

????? /* Normal mutex.? Nothing special to do.? */

????? break;

??? }

? /* Always reset the owner field.? */

? mutex->__data.__owner = 0;

? if (decr)

??? /* One less user.? */

??? --mutex->__data.__nusers;

? /* Unlock.? */

? lll_mutex_unlock (mutex->__data.__lock);

? return 0;

}

省略部分是针对不同的__kind属性值做的一些处理,最终调用 lll_mutex_unlock。

该宏函数最终的定义为:

#define __lll_mutex_unlock(futex)????????????????????????\

? ((void) ({????????????????????????????????????????????????\

??? int *__futex = (futex);????????????????????????????????\

??? int __val = atomic_exchange_rel (__futex, 0);????????\

\

??? if (__builtin_expect (__val > 1, 0))????????????????\

????? lll_futex_wake (__futex, 1);????????????????????????\

? }))

atomic_exchange_rel (__futex, 0);宏为:

#define atomic_exchange_rel(mem, value) \

? (__sync_synchronize (), __sync_lock_test_and_set (mem, value))

实现功能为:将mem设置为value,返回原始mem值。

__builtin_expect (__val > 1, 0) 是编译器优化语句,告诉编译器期望值,也就是大多数情况下__val > 1 ?是0,其逻辑判断依然为if(__val > 1)为真的话执行 lll_futex_wake。

现在分析,在资源没有被竞争的情况下,__futex 为1,那么返回值__val则为1,那么 lll_futex_wake (__futex, 1);????????不会被执行,不产生系统调用。 当资源产生竞争的情况时,根据对pthread_mutex_lock 函数的分析,__futex为2, __val则为2,执行 lll_futex_wake (__futex, 1); 从而唤醒等在临界资源的线程。

lll_futex_wake (__futex, 1); 最终会调动同一个系统调用,即futex, 只是传递的cmd参数为FUTEX_WAKE。

在linux kernel的futex实现中,调用

static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset)

{

struct futex_hash_bucket *hb;

struct futex_q *this, *next;

struct plist_head *head;

union futex_key key = FUTEX_KEY_INIT;

int ret;

if (!bitset)

return -EINVAL;

ret = get_futex_key(uaddr, fshared, &key);

if (unlikely(ret != 0))

goto out;

hb = hash_futex(&key);

spin_lock(&hb->lock);

head = &hb->chain;

plist_for_each_entry_safe(this, next, head, list) {

if (match_futex (&this->key, &key)) {

if (this->pi_state || this->rt_waiter) {

ret = -EINVAL;

break;

}

/* Check if one of the bits is set in both bitsets */

if (!(this->bitset & bitset))

continue;

wake_futex(this);

if (++ret >= nr_wake)

break;

}

}

spin_unlock(&hb->lock);

put_futex_key(fshared, &key);

out:

return ret;

}

该函数遍历在该mutex上休眠的所有线程,调用wake_futex进行唤醒,

static void wake_futex(struct futex_q *q)

{

struct task_struct *p = q->task;

/*

?* We set q->lock_ptr = NULL _before_ we wake up the task. If

?* a non futex wake up happens on another CPU then the task

?* might exit and p would dereference a non existing task

?* struct. Prevent this by holding a reference on p across the

?* wake up.

?*/

get_task_struct(p);

plist_del(&q->list, &q->list.plist);

/*

?* The waiting task can free the futex_q as soon as

?* q->lock_ptr = NULL is written, without taking any locks. A

?* memory barrier is required here to prevent the following

?* store to lock_ptr from getting ahead of the plist_del.

?*/

smp_wmb();

q->lock_ptr = NULL;

wake_up_state(p, TASK_NORMAL);

put_task_struct(p);

}

wake_up_state(p, TASK_NORMAL);? 的实现位于kernel/sched.c中,属于linux进程调度的技术。

操作系统消费者进程中,wait(full)和wait(mutex)顺序不能颠倒?

1、首先,缓冲池为空,就没有产品。full=0,这里还要强调,mutex是全局互斥信号量。
2、这个时候先来了个消费者,他的程序如下:wait(mutex);挂起了,并且占用了mutex,wait(full);不管来多少消费者,都在mutex队列排队,死锁了。
3、这个时候生产者的程序wait(empty);可行wait(mutex)也挂起了, 因为mutex给消费者用了,就是说缓冲区给消费者占用了啦!生产者和消费者都等待了,系统死锁了。

Mutex和信号量的区别

mutex的设计目的是"持有后快速释放",也就是说如果一个竞争者在获取失败后,会spin几个循环后再尝试,如果仍然失败,则进入睡眠,这相当于semaphore获取失败后直接睡眠,多了一个spin过程,所以如果每个mutex在持有后又很快释放,那么就不存在CPU的唤醒过程。这显然比semaphore快很多。具体参考https://github.com/torvalds/linux/blob/master/kernel/locking/mutex.c

计算机操作系统互斥信号量mutex怎么解释

一般mutex为1,0,-1,……,
1表示程序可以进入临界区,可以执行p操作,但执行后要令1变为0

网站数据信息

"mutex,深入理解mutex工作机制"浏览人数已经达到20次,如你需要查询该站的相关权重信息,可以点击进入"Chinaz数据" 查询。更多网站价值评估因素如:mutex,深入理解mutex工作机制的访问速度、搜索引擎收录以及索引量、用户体验等。 要评估一个站的价值,最主要还是需要根据您自身的需求,如网站IP、PV、跳出率等!