说明:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
QQ 群 号:513683159 【相互学习】
内容来源:
《多线程编程指南》
互斥锁
作用:可使线程按顺序执行。
①确保一次只有一个线程执行代码的临界段来同步多个线程。
②保护单线程代码。
使用:设置在应用程序开头某处,以便查找和修改。
文章目录
- 互斥锁
- 初始化互斥锁属性对象:pthread_mutexattr_init ()
- 销毁互斥锁属性对象:pthread_mutexattr_destroy()
- 初始化互斥锁:pthread_mutex_init()
- 使互斥保持一致:pthread_mutex_consistent_np()
- 锁定互斥锁:pthread_mutex_lock()
- 解除锁定互斥锁 :pthread_mutex_unlock()
- 使用非阻塞互斥锁锁定:pthread_mutex_trylock()
- 销毁互斥锁:pthread_mutex_destroy()
- 设置互斥锁的范围:pthread_mutexattr_setpshared()
- 获取互斥锁的范围:pthread_mutexattr_getpshared()
- 设置互斥锁类型的属性:pthread_mutexattr_settype()
- 获取互斥锁的类型属性:pthread_mutexattr_gettype()
- 设置互斥锁属性的协议:pthread_mutexattr_setprotocol()
- 获取互斥锁属性的协议 :pthread_mutexattr_getprotocol()
- 设置互斥锁属性的优先级上限:pthread_mutexattr_setprioceiling()
- 获取互斥锁属性的优先级上限 :pthread_mutexattr_getprioceiling()
- 设置互斥锁的强健属性:pthread_mutexattr_setrobust_np()
- 获取互斥锁的强健属性:pthread_mutexattr_getrobust_np()
初始化互斥锁属性对象:pthread_mutexattr_init ()
1.函数功能:可将与互斥锁属性对象__attr
相关联的属性初始化为其缺省值。在执行过程中,线程系统会为每个属性对象分配存储空间。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr) __THROW __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.错误代码:
ENOMEM
:内存不足,无法初始化互斥锁属性对象。
销毁互斥锁属性对象:pthread_mutexattr_destroy()
1.函数功能可用来取消分配用于维护pthread_mutexattr_init()
所创建的属性对象的存储空间。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) __THROW __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.错误代码:
EINVAL
:由mattr
指定的值无效。
初始化互斥锁:pthread_mutex_init()
1.函数功能:可使用缺省值初始化由__mutex
所指向的互斥锁,还可指定已经使用pthread_mutexattr_init()
设置的互斥锁属性。__mutexattr
的缺省值为NULL
。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutex_init (pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr) __THROW __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __mutex:互斥锁 |
__mutexattr:互斥锁属性 | |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 | ①初始化互斥锁之前,需将其所在内存清零 ②若互斥锁已初始化,则会处于未锁定状态。 ③互斥锁可位于进程之间共享的内存中或某个进程的专用内存中。 ④__mutexattr设置NULL效果与传递缺省互斥锁属性对象的地址相同,但无内存开销 ⑤使用PTHREAD_MUTEX_INITIALIZER宏可以将以静态方式定义的互斥锁初始化为其缺省属性。 ⑥当其他线程正在使用某个互斥锁时,请勿重新初始化或销毁该互斥锁。若任一操作没有正确完成,将会导致程序失败。若要重新初始化或销毁某个互斥锁,则应用程序必须确保当前未使用该互斥锁。 |
2.错误代码:
EBUSY
:该实现已检测到系统尝试重新初始化__mutex
所引用的对象,即以前进行过初始化但尚未销毁的互斥锁。
EINVAL
: __mutexattr
属性值无效。互斥锁尚未修改。
EFAULT
:__mutex
所指向的互斥锁的地址无效。
使互斥保持一致:pthread_mutex_consistent_np()
1.函数功能:如果某个互斥锁的属主失败,该互斥锁可能会变为不一致。
该函数可使互斥对象__mutex
在其属主停止之后保持一致。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutex_consistent_np (pthread_mutex_t *__mutex) __THROW __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __mutex:互斥锁 |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.错误代码:
ENOSYS
:选项_POSIX_ THREAD_PRIO_INHERIT
未定义,或者该实现不支持pthread_mutex_consistent_np( )
。
EINVAL
:__mutex
属性值无效。
锁定互斥锁:pthread_mutex_lock()
1.函数功能:可以锁定__mutex
所指向的互斥锁。
当pthread_mutex_lock()
返回时,该互斥锁已被锁定。调用线程是该互斥锁的属主。如果该互斥锁已被另一个线程锁定和拥有,则调用线程将阻塞,直到该互斥锁变为可用为止。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutex_lock (pthread_mutex_t *__mutex) __THROWNL __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __mutex:互斥锁 |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.注意事项:
1️⃣若互斥锁类型为PTHREAD_MUTEX_NORMAL
,则不提供死锁检测。尝试重新锁定互斥锁会导致死锁。如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或未锁定,则将产生不确定的行为。
2️⃣若互斥锁类型为PTHREAD_MUTEX_ERRORCHECK
,则会提供错误检查。如果某个线程尝试重新锁定的互斥锁已经由该线程锁定,则将返回错误。如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或者未锁定,则将返回错误。
3️⃣若互斥锁类型为PTHREAD_MUTEX_RECURSIVE
,则该互斥锁会保留锁定计数这一概念。线程首次成功获取互斥锁时,锁定计数会设置为1。线程每重新锁定该互斥锁一次,锁定计数就增加1。线程每解除锁定该互斥锁一次,锁定计数就减小1。锁定计数达到0时,该互斥锁即可供其他线程获取。如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或者未锁定,则将返回错误。
4️⃣若互斥锁类型是PTHREAD_MUTEX_DEFAULT
,则尝试以递归方式锁定该互斥锁将产生不确定的行为。对于不是由调用线程锁定的互斥锁,如果尝试解除对它的锁定,则会产生不确定的行为。如果尝试解除锁定尚未锁定的互斥锁,则会产生不确定的行为。
3.错误代码:
EAGAIN
:由于已超出了互斥锁递归锁定的最大次数,因此无法获取该互斥锁。
EDEADLK
:当前线程已经拥有互斥锁。
解除锁定互斥锁 :pthread_mutex_unlock()
1.函数功能:可解除锁定__mutex
所指向的互斥锁,释放__mutex
引用的互斥锁对象。
互斥锁的释放方式取决于互斥锁的类型属性。
若调用pthread_mutex_unlock()
时有多个线程被__mutex
对象阻塞,则互斥锁变为可用时调度策略可确定获取该互斥锁的线程。对于PTHREAD_MUTEX_RECURSIVE
类型的互斥锁,当计数达到零并且调用线程不再对该互斥锁进行任何锁定时,该互斥锁将变为可用。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROWNL __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __mutex:互斥锁 |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.错误代码:
EPERM
:当前线程不拥有互斥锁。
使用非阻塞互斥锁锁定:pthread_mutex_trylock()
1.函数功能:可尝试锁定__mutex
所指向的互斥锁。
pthread_mutex_trylock()
是pthread_mutex_lock()
的非阻塞版本。如果__mutex
所引用的互斥对象当前被任何线程(包括当前线程)锁定,则将立即返回该调用。否则,该互斥锁将处于锁定状态,调用线程是其属主。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutex_trylock (pthread_mutex_t *__mutex) __THROWNL __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __mutex:互斥锁 |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.错误代码:
EBUSY
:由于__mutex
所指向的互斥锁已锁定,因此无法获取该互斥锁。
EAGAIN
:由于已超出了__mutex
的递归锁定最大次数,因此无法获取该互斥锁。
销毁互斥锁:pthread_mutex_destroy()
1.函数功能:可销毁与__mutex
所指向的互斥锁相关联的任何状态。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) __THROW __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __mutex:互斥锁 |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.错误代码:
EINVAL
:__mutex
指定的值不会引用已初始化的互斥锁对象。
设置互斥锁的范围:pthread_mutexattr_setpshared()
1.函数功能:可用来设置互斥锁变量的作用域,通过设置互斥锁属性ATTR
的进程共享标志。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, int __pshared) __THROW __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
__pshared:共享标志 | |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.共享标志:
PTHREAD_PROCESS_SHARED
:若在共享内存中创建互斥锁,设置该标记,可实现在多个进程中的线程之间共享互斥锁。
PTHREAD_PROCESS_PRIVATE
:则仅有那些由同一个进程创建的线程才能够处理该互斥锁。
3.错误代码:
EINVAL
:由mattr
指定的值无效。
获取互斥锁的范围:pthread_mutexattr_getpshared()
1.函数功能:可用来返回由pthread_mutexattr_setpshared()
定义的互斥锁变量的范围,即获取互斥锁属性ATTR
的进程共享标志。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_getpshared (const pthread_mutexattr_t * __restrict __attr, int *__restrict __pshared) __THROW __nonnull ((1, 2)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
__pshared:共享标志 | |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.错误代码:
EINVAL
:由mattr
指定的值无效。
设置互斥锁类型的属性:pthread_mutexattr_settype()
1.函数功能:可用来设置互斥锁的type
属性。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind) __THROW __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
__kind:互斥锁类型 默认为PTHREAD_MUTEX_DEFAULT | |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.互斥锁类型:
1️⃣PTHREAD_MUTEX_NORMAL
此类型的互斥锁不会检测死锁。如果线程在不首先解除互斥锁的情况下尝试重新锁定该互斥锁,则会产生死锁。尝试解除由其他线程锁定的互斥锁会产生不确定的行为。如果尝试解除锁定的互斥锁未锁定,则会产生不确定的行为。
2️⃣PTHREAD_MUTEX_ERRORCHECK
此类型的互斥锁可提供错误检查。如果线程在不首先解除锁定互斥锁的情况下尝试重新锁定该互斥锁,则会返回错误。如果线程尝试解除锁定的互斥锁已经由其他线程锁定,则会返回错误。如果线程尝试解除锁定的互斥锁未锁定,则会返回错误。
3️⃣PTHREAD_MUTEX_RECURSIVE
如果线程在不首先解除锁定互斥锁的情况下尝试重新锁定该互斥锁,则可成功锁定该互斥锁。与PTHREAD_MUTEX_NORMAL
类型的互斥锁不同,对此类型互斥锁进行重新锁定时不会产生死锁情况。多次锁定互斥锁需要进行相同次数的解除锁定才可以释放该锁,然后其他线程才能获取该互斥锁。如果线程尝试解除锁定的互斥锁已经由其他线程锁定,则会返回错误。如果线程尝试解除锁定的互斥锁未锁定,则会返回错误。
4️⃣PTHREAD_MUTEX_DEFAULT
如果尝试以递归方式锁定此类型的互斥锁,则会产生不确定的行为。对于不是由调用线程锁定的此类型互斥锁,如果尝试对它解除锁定,则会产生不确定的行为。对于尚未锁定的此类型互斥锁,如果尝试对它解除锁定,也会产生不确定的行为。允许在实现中将该互斥锁映射到其他互斥锁类型之一。
3.错误代码:
EINVAL
:由__attr
指定的值无效 或 __kind
的值无效。
获取互斥锁的类型属性:pthread_mutexattr_gettype()
1.函数功能:可用来获取由pthread_mutexattr_settype()
设置的互斥锁的__kind
属性。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_gettype (const pthread_mutexattr_t *__restrict __attr, int *__restrict __kind) __THROW __nonnull ((1, 2)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
__kind:互斥锁类型变量地址 | |
返回值 | 成功返回0,失败返回非零 |
注意 |
设置互斥锁属性的协议:pthread_mutexattr_setprotocol()
1.函数功能:可用来设置互斥锁属性对象的协议属性。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_setprotocol (pthread_mutexattr_t *__attr, int __protocol) __THROW __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
__protocol:互斥锁属性协议类型 | |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.互斥锁属性协议类型:
1️⃣PTHREAD_PRIO_NONE
线程的优先级和调度不会受到互斥锁拥有权的影响。
2️⃣PTHREAD_PRIO_INHERIT
此协议值(如thrd1)会影响线程的优先级和调度。如果更高优先级的线程因thrd1所拥有的一个或多个互斥锁而被阻塞,而这些互斥锁是用PTHREAD_PRIO_INHERIT
初始化的,则thrd1将以高于它的优先级或者所有正在等待这些互斥锁(这些互斥锁是thrd1指所拥有的互斥锁)的线程的最高优先级运行。
如果thrd1
因另一个线程(thrd3)拥有的互斥锁而被阻塞,则相同的优先级继承效应会以递归方式传播给thrd3
。
使用PTHREAD_PRIO_INHERIT
可以避免优先级倒置。低优先级的线程持有较高优先级线程所需的锁时,便会发生优先级倒置。只有在较低优先级的线程释放该锁之后,较高优先级的线程才能继续使用该锁。设置PTHREAD_PRIO_INHERIT
,以便按与预期的优先级相反的优先级处理每个线程。
如果为使用协议属性值PTHREAD_PRIO_INHERIT
初始化的互斥锁定义了_POSIX_THREAD_PRIO_INHERIT
,则互斥锁的属主失败时会执行以下操作。属主失败时的行为取决于pthread_mutexattr_setrobust_np()
的robustness
参数的值。
①解除锁定互斥锁。
②互斥锁的下一个属主将获取该互斥锁,并返回错误EOWNERDEAD
。
③互斥锁的下一个属主会尝试使该互斥锁所保护的状态一致。如果上一个属主失败,则状态可能会不一致。如果属主成功使状态保持一致,则可针对该互斥锁调用pthread_mutex_init( )
并解除锁定该互斥锁。
注-如果针对以前初始化的但尚未销毁的互斥锁调用pthread_mutex_init(),则该互斥锁不会重新初始化。
④如果属主无法使状态保持一致,请勿调用pthread_mutex_init()
,而是解除锁定该互斥锁。在这种情况下,所有等待的线程都将被唤醒。以后对pthread_mutex_lock()
的所有调用将无法获取互斥锁,并将返回错误代码ENOTRECOVERABLE
。现在,通过调用pthread_mutex_destroy()
来取消初始化该互斥锁,即可使其状态保持一致。调用pthread_mutex_init()
可重新初始化互斥锁。
⑤如果已获取该锁的线程失败并返回EOWNERDEAD
,则下一个属主将获取该锁及错误代码EOWNERDEAD
。
3️⃣PTHREAD_PRIO_PROTECT
当线程拥有一个或多个使用PTHREAD_PRIO_PROTECT
初始化的互斥锁时,此协议值会影响其他线程(如thrd2)的优先级和调度。thrd2以其较高的优先级或者以thrd2拥有的所有互斥锁的最高优先级上限运行。基于被thrd2拥有的任一互斥锁阻塞的较高优先级线程对于thrd2的调度没有任何影响。
如果某个线程调用sched_setparam()来更改初始优先级,则调度程序不会采用新优先级将该线程移到调度队列末尾。
线程拥有使用PTHREAD_PRIO_INHERIT
或PTHREAD_PRIO_PROTECT
初始化的互斥锁
线程解除锁定使用PTHREAD_PRIO_INHERIT
或PTHREAD_PRIO_PROTECT
初始化的互斥锁
一个线程可以同时拥有多个混合使用PTHREAD_PRIO_INHERIT
和PTHREAD_PRIO_PROTECT
初始化的互斥锁。在这种情况下,该线程将以通过其中任一协议获取的最高优先级执行。
3.错误代码:
ENOSYS
:选项_POSIX_ THREAD_PRIO_INHERIT
和_POSIX_THREAD_PRIO_PROTECT
均未定义并且该实现不支持此函数。
ENOTSUP
:protocol
指定的值不受支持。如果出现以下任一情况,pthread_mutexattr_setprotocol()
可能会失败并返回对应的值。
EINVAL
: attr
或protocol
指定的值无效。
EPERM
:调用方无权执行该操作。
获取互斥锁属性的协议 :pthread_mutexattr_getprotocol()
1.函数功能:可用来获取互斥锁属性对象的协议属性。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_getprotocol (const pthread_mutexattr_t * __restrict __attr, int *__restrict __protocol) __THROW __nonnull ((1, 2)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
__protocol: | |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
3.错误代码:
ENOSYS
:_POSIX_THREAD_PRIO_INHERIT
选项和_POSIX_THREAD_PRIO_PROTECT
选项均未定义并且该实现不支持此函数。
如果出现以下任一情况,pthread_mutexattr_getprotocol()
可能会失败并返回对应的值。
EINVAL
:attr
指定的值无效。
EPERM
:调用方无权执行该操作。
设置互斥锁属性的优先级上限:pthread_mutexattr_setprioceiling()
1.函数功能:可用来设置互斥锁属性对象的优先级上限属性,即将*ATTR
中的互斥锁prioceiling
属性设置为prioceiling
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_setprioceiling (pthread_mutexattr_t *__attr, int __prioceiling) __THROW __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
__prioceiling:指定已初始化互斥锁的优先级上限 优先级上限定义执行互斥锁保护的临界段时的最低优先级。prioceiling位于SCHED_FIFO所定义的优先级的最大范围内。要避免优先级倒置,请将prioceiling设置为高于或等于可能会锁定特定互斥锁的所有线程的最高优先级。 | |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.错误代码:
ENOSYS
:选项_POSIX_THREAD_PRIO_PROTECT
未定义并且该实现不支持此函数。
如果出现以下任一情况,pthread_mutexattr_setprioceiling()
可能会失败并返回对应的值。
EINVAL
: attr
或prioceiling
指定的值无效。
EPERM
:调用方无权执行该操作。
获取互斥锁属性的优先级上限 :pthread_mutexattr_getprioceiling()
1.函数功能:可用来获取互斥锁属性对象的优先级上限属性。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_getprioceiling (const pthread_mutexattr_t * __restrict __attr, int *__restrict __prioceiling) __THROW __nonnull ((1, 2)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
__prioceiling: | |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.错误代码:
ENOSYS
:_POSIX_THREAD_PRIO_PROTECT
选项未定义并且该实现不支持此函数。
如果出现以下任一情况,pthread_mutexattr_getprioceiling()
可能会失败并返回对应的值。
EINVAL
:attr
指定的值无效。
EPERM
:调用方无权执行该操作。
设置互斥锁的强健属性:pthread_mutexattr_setrobust_np()
1.函数功能:可用来设置互斥锁属性对象的强健属性。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_setrobust_np (pthread_mutexattr_t *__attr, int __robustness) __THROW __nonnull ((1)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
__robustness:互斥锁属性对象的强健属性值 | |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.错误代码:
ENOSYS
:选项_POSIX_ THREAD_PRIO__INHERIT
未定义,或者该实现不支持pthread_mutexattr_setrobust_np()
。
ENOTSUP
:robustness
指定的值不受支持。
EINVAL
:attr
或robustness
指定的值无效。
获取互斥锁的强健属性:pthread_mutexattr_getrobust_np()
1.函数功能:可用来获取互斥锁属性对象的强健属性。
项目 | 说明 |
---|---|
函数原型 | extern int pthread_mutexattr_getrobust_np (const pthread_mutexattr_t *__attr, int *__robustness) __THROW __nonnull ((1, 2)); |
头文件 | pthread.h |
参数说明 | __attr:属性对象 pthread_mutexattr_t类型变量地址 |
__robustness:互斥锁属性对象的强健属性值 | |
返回值 | 成功返回0,失败返回非零,并设置errno以指示错误状态。 |
注意 |
2.错误代码:
ENOSYS
:选项_POSIX_THREAD_PRIO__INHERIT
未定义,或者该实现不支持pthread_mutexattr_getrobust_np()
。
EINVAL
: attr或robustness指定的值无效。