C/C++_多核多线程编程_互斥锁

前言

文档分为四个部分。
第一部分:前言;
第二部分:描述要解决的问题也即是描述为什么会有互斥锁,以及有什么用,定义,互斥锁是什么;
第三部分:互斥锁用法,怎么用,;
第四部分:demo;
参考链接:http://www.cnblogs.com/diyingyun/archive/2011/12/04/2275229.html
参考链接:https://baike.so.com/doc/4995542-5219667.html

定义/概念

问题的出现

在现代操作系统中,出现不止一个对象(进程/线程)对代码进行访问是一个普遍的现象(并发的来源),这也就会出现对共享的资源(内存、硬件资源等)出现竞争占有的状态(竞态)。资源是必须用于多个对象共享的,但是我们又不能让多个对象同时占有资源(即竞态的发生),那么这时候就必须有一个操作,保证一个对象访问资源时,其他对象无法访问资源,这样互斥锁也就应运而生。
在系统设计,代码设计上,我们一直在避免竞态的发生,比如将硬件内存映射为虚拟内存(避免进程间资源的访问),比如将内存分为堆/栈/动态栈等(将资源存放的地方分开),比如将减少对全局变量的定义(不让其被更多对象访问到)。通过互斥的操作,我们做到一次只有一个执行线程访问共享的资源。

定义

互斥锁:对资源进行锁定,保证只有一个访问者对资源进行访问,但是无法限制访问者对资源的访问顺序,访问是无序的;

用法

环境

计算机语言:C++;
系统:Android N;

使用流程

对于互斥锁的使用流程可以抽象为以下几个步骤:

  • 创建 Create

  • 加锁 Lock

  • 解锁 Unlock

  • 销毁 Destroy

在创建锁之前,要添加头文件:#include
使用pthread_mutex_init()对锁进行初始化;
使用pthread_mutex_lock()对锁进行上锁;
使用pthread_mutex_unlock()对锁进行解锁;
使用pthread_mutex_destroy()对锁进行销毁;

函数具体说明

pthread_mutex_init

函数原型:int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
参数1:我们自己声明的锁变量;
参数2:新建的锁的属性,一般为空,使用默认的锁类型,默认是快速互斥锁;
该函数用于C函数的多线程编程中,对互斥锁的动态初始化。
不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。

pthread_mutex_init()函数成功完成之后会返回零,其他任何返回值都表示出现了错误。

函数成功执行后,互斥锁被初始化为未锁住态。

pthread_mutexattr_init

函数原型:int pthread_mutexattr_init(pthread_mutexattr_t *mattr);
参数1:互斥锁的属性;
使用pthread_mutexattr_init()可以将与互斥锁对象相关联的属性初始化为其缺省值,也就是将pthread_mutex_init的参数2设置为缺省值。在执行过程中,线程系统会为每个属性对象分配存储空间。

#include 

pthread_mutexattr_t mattr;

int ret;/* initialize an attribute to default value */

ret = pthread_mutexattr_init(&mattr);

调用此函数时,pshared 属性的缺省值为 PTHREAD_PROCESS_PRIVATE。 该值表示可以在进程内使用经过初始化的互斥锁。
mattr 的类型为 opaque,其中包含一个由系统分配的属性对象。mattr 范围可能的值为 PTHREAD_PROCESS_PRIVATE 和 PTHREAD_PROCESS_SHARED。PTHREAD_PROCESS_PRIVATE 是缺省值。
对于互斥锁属性对象,必须首先通过调用 pthread_mutexattr_destroy() 将其销毁,才能重新初始化该对象。pthread_mutexattr_init() 调用会导致分配类型为 opaque 的对象。如果未销毁该对象,则会导致内存泄漏。

pthread_mutexattr_destroy

函数原型:int pthread_mutexattr_destroy(pthread_mutexattr_t *mattr)
参数1:互斥锁的属性;
pthread_mutexattr_destroy()用来销毁 pthread_mutexattr_init() 所创建的属性对象的存储空间。

#include 

pthread_mutexattr_t mattr;

int ret;/* destroy an attribute */

ret = pthread_mutexattr_init(&mattr);

ret = pthread_mutexattr_destroy(&mattr);

pthread_mutexattr_destroy() 成功完成之后会返回零。其他任何返回值都表示出现了错误。如果出现以下情况,该函数将失败并返回对应的值。
EINVAL 描述: 由 mattr 指定的值无效。

pthread_mutexattr_setpshared

函数原型:int pthread_mutexattr_setpshared(pthread_mutexattr_t *mattr, int pshared);
参数1:互斥锁的属性;
参数2:指定互斥锁的作用域的类型,有两种,PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED默认是PTHREAD_PROCESS_PRIVATE;
pthread_mutexattr_setpshared()可用来设置互斥锁变量的作用域。
互斥锁变量可以是进程专用的(进程内)变量,也可以是系统范围内的(进程间)变量。要在多个进程中的线程之间共享互斥锁,可以在共享内存中创建互斥锁,并将pshared属性设置为 PTHREAD_PROCESS_SHARED。

#include 

pthread_mutexattr_t mattr;

int ret;

ret = pthread_mutexattr_init(&mattr); /* * resetting to its default value: private */

ret = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_PRIVATE);

pthread_mutexattr_getpshared

函数原型:int pthread_mutexattr_getpshared(pthread_mutexattr_t *mattr, int *pshared);
参数1:互斥锁的属性;
参数2:指定互斥锁的作用域的类型,有两种,PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED默认是PTHREAD_PROCESS_PRIVATE;

pthread_mutexattr_getpshared()可用来返回由 pthread_mutexattr_setpshared() 定义的互斥锁变量的范围。

此函数可为属性对象 mattr 获取 pshared 的当前值。该值为 PTHREAD_PROCESS_SHARED 或 PTHREAD_PROCESS_PRIVATE。

pthread_mutexattr_getpshared() 成功完成之后会返回零。其他任何返回值都表示出现了错误。如果出现以下情况,该函数将失败并返回对应的值。

EINVAL 描述: 由 mattr 指定的值无效。


#include 

pthread_mutexattr_t mattr;

int pshared, ret;/* get pshared of mutex */

ret = pthread_mutexattr_getpshared(&mattr, &pshared);

pthread_mutexattr_settype

函数原型:int pthread_mutexattr_settype(pthread_mutexattr_t *attr , int type);
参数1:互斥锁的属性;
参数2:互斥锁的type属性,决定不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。
pthread_mutexattr_settype()可用来设置互斥锁的type属性。

类型属性的缺省值为 PTHREAD_MUTEX_DEFAULT。
type参数指定互斥锁的类型。以下列出了有效的互斥锁类型:

PTHREAD_MUTEX_NORMAL 描述: 此类型的互斥锁不会检测死锁。如果线程在不首先解除互斥锁的情况下尝试重新锁定该互斥锁,则会产生死锁。尝试解除由其他线程锁定的互斥锁会产生不确定的行为。如果尝试解除未锁定的互斥锁,则会产生不确定的行为。

PTHREAD_MUTEX_ERRORCHECK 描述: 此类型的互斥锁可提供错误检查。如果线程在不首先解除锁定互斥锁的情况下尝试重新锁定该互斥锁,则会返回错误。如果线程尝试解除锁定的互斥锁已经由其他线程锁定,则会返回错误。如果线程尝试解除未锁定的互斥锁,则会返回错误。

PTHREAD_MUTEX_RECURSIVE 描述: 如果线程在不首先解除锁定互斥锁的情况下尝试重新锁定该互斥锁,则可成功锁定该互斥锁。 与 PTHREAD_MUTEX_NORMAL 类型的互斥锁不同,对此类型互斥锁进行重新锁定时不会产生死锁情况。多次锁定互斥锁需要进行相同次数的解除锁定才可以释放该锁,然后其他线程才能获取该互斥锁。如果线程尝试解除锁定的互斥锁已经由其他线程锁定,则会返回错误。 如果线程尝试解除未锁定的互斥锁,则会返回错误。

PTHREAD_MUTEX_DEFAULT 描述: 如果尝试以递归方式锁定此类型的互斥锁,则会产生不确定的行为。对于不是由调用线程锁定的此类型互斥锁,如果尝试对它解除锁定,则会产生不确定的行为。对于尚未锁定的此类型互斥锁,如果尝试对它解除锁定,也会产生不确定的行为。允许在实现中将该互斥锁映射到其他互斥锁类型之一。对于 Solaris 线程,PTHREAD_PROCESS_DEFAULT 会映射到 PTHREAD_PROCESS_NORMAL。

如果运行成功,pthread_mutexattr_settype 函数会返回零。否则,将返回用于指明错误的错误号。

EINVAL 描述: 值为 type 无效。EINVAL 描述: attr 指定的值无效。

pthread_mutexattr_gettype

函数原型:int pthread_mutexattr_gettype(pthread_mutexattr_t *attr , int *type);
参数1:互斥锁的属性;
参数2:互斥锁的type属性,决定不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。
pthread_mutexattr_gettype()可用来获取由 pthread_mutexattr_settype() 设置的互斥锁的type属性。

类型属性的缺省值为 PTHREAD_MUTEX_DEFAULT。

type参数指定互斥锁的类型。有效的互斥锁类型包括:

PTHREAD_MUTEX_NORMAL PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_DEFAULT 有关每种类型的说明,请参见pthread_mutexattr_settype 语法。

如果成功完成,pthread_mutexattr_gettype() 会返回 0。其他任何返回值都表示出现了错误。

pthread_mutexattr_setprotocol

函数原型:int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol);
参数1:指示以前调用 pthread_mutexattr_init() 时创建的互斥锁属性对象;
参数2:protocol 可定义应用于互斥锁属性对象的协议;
pthread.h 中定义的 protocol 可以是以下值之一:PTHREAD_PRIO_NONE、PTHREAD_PRIO_INHERIT 或 PTHREAD_PRIO_PROTECT。
PTHREAD_PRIO_NONE :线程的优先级和调度不会受到互斥锁拥有权的影响。
PTHREAD_PRIO_INHERIT:此协议值会影响线程的优先级和调度。如果更高优先级的线程,如线程2 ,因 线程1 所拥有的一个或多个互斥锁而被阻塞,而这些互斥锁是用 PTHREAD_PRIO_INHERIT 初始化的,则 线程1 将以高于它的优先级(拥有线程2 的优先级)或者所有正在等待这些互斥锁(这些互斥锁是 线程1 所拥有的互斥锁)的线程的最高优先级运行。如果 线程1 因另一个线程 (线程3) 拥有的互斥锁而被阻塞,则相同的优先级继承效应会以递归方式传播给 线程3。使用 PTHREAD_PRIO_INHERIT 可以避免优先级倒置。低优先级的线程持有较高优先级线程所需的锁时,便会发生优先级倒置,这样可以保证持有锁的线程以较高的优先级运行。只有在较低优先级的线程释放该锁之后,较高优先级的线程才能继续使用该锁。如果为使用协议属性值 PTHREAD_PRIO_INHERIT 初始化的互斥锁定义了 _POSIX_THREAD_PRIO_INHERIT,则互斥锁的属主失败时会根据pthread_mutexattr_setrobust_np() 的 robustness 参数的值做出相应的行为。
如果成功完成,pthread_mutexattr_setprotocol() 会返回 0。其他任何返回值都表示出现了错误。

如果出现以下任一情况,pthread_mutexattr_setprotocol() 将失败并返回对应的值。

ENOSYS 描述: 选项 _POSIX_THREAD_PRIO_INHERIT 和 _POSIX_THREAD_PRIO_PROTECT 均未定义并且该实现不支持此函数。 ENOTSUP 描述: protocol 指定的值不受支持。 如果出现以下任一情况,pthread_mutexattr_setprotocol() 可能会失败并返回对应的值。

EINVAL 描述: attr 或 protocol 指定的值无效。EPERM 描述: 调用方无权执行该操作。

pthread_mutexattr_getprotocol

pthread_mutexattr_getprotocol()可用来获取互斥锁属性对象的协议属性。
函数原型:int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol);
参数1:指示以前调用 pthread_mutexattr_init() 时创建的互斥锁属性对象;
参数2:protocol 包含以下协议属性之一:PTHREAD_PRIO_NONE、PTHREAD_PRIO_INHERIT 或 PTHREAD_PRIO_PROTECT;
如果成功完成,pthread_mutexattr_getprotocol() 会返回 0。其他任何返回值都表示出现了错误。

如果出现以下情况,pthread_mutexattr_getprotocol() 将失败并返回对应的值。

ENOSYS 描述: _POSIX_THREAD_PRIO_INHERIT 选项和 _POSIX_THREAD_PRIO_PROTECT 选项均未定义并且该实现不支持此函数。 如果出现以下任一情况,pthread_mutexattr_getprotocol() 可能会失败并返回对应的值。

EINVAL 描述: attr 指定的值无效。EPERM 描述: 调用方无权执行该操作。

pthread_mutexattr_setprioceiling

函数原型:int pthread_mutexattr_setprioceiling(pthread_mutexatt_t *attr, int prioceiling, int *oldceiling);
参数1:指示以前调用 pthread_mutexattr_init() 时创建的互斥锁属性对象;
参数2:指定已初始化互斥锁的优先级上限。优先级上限定义执行互斥锁保护的临界段时的最低优先级。prioceiling 位于 SCHED_FIFO 所定义的优先级的最大范围内。要避免优先级倒置(阻塞的线程优先级高于持有锁的优先级),请将 prioceiling 设置为高于或等于可能会锁定特定互斥锁的所有线程的最高优先级。
pthread_mutexattr_setprioceiling()可用来设置互斥锁属性对象的优先级上限属性。
看了下网上的资料,这里的用法还不怎么理解,还有一些是硬件不支持的,下面有个demo,示例测试系统支不支持这个特性:

int main(void)
{

    /* Make sure there is prioceiling capability. */
    /* #ifndef _POSIX_PRIORITY_SCHEDULING
       fprintf(stderr,"prioceiling attribute is not available for testing\n");
       return PTS_UNRESOLVED;
       #endif */

    pthread_mutexattr_t mta;
    int prioceiling, ret;

    prioceiling = sched_get_priority_min(SCHED_FIFO);

    /* Set the prioceiling of an unintialized mutex attr. */
    if ((ret = pthread_mutexattr_setprioceiling(&mta, prioceiling)) == 0) {
        printf
            ("Test PASSED: *Note: Returned 0 instead of EINVAL when passed an uninitialized mutex attribute object to pthread_mutexattr_setprioceiling, but standard says 'may' fail.\n");
        return PTS_PASS;
    }

    if (ret != EINVAL) {
        printf
            ("Test FAILED: Invalid return code %d. Expected EINVAL or 0.\n",
             ret);
        return PTS_FAIL;
    }

    printf("Test PASSED\n");
    return PTS_PASS;
}

如果成功完成,pthread_mutexattr_setprioceiling() 会返回 0。其他任何返回值都表示出现了错误。

如果出现以下任一情况,pthread_mutexattr_setprioceiling() 将失败并返回对应的值。

ENOSYS 描述: 选项 _POSIX_THREAD_PRIO_PROTECT 未定义并且该实现不支持此函数。 如果出现以下任一情况,pthread_mutexattr_setprioceiling() 可能会失败并返回对应的值。

EINVAL 描述: attr 或 prioceiling 指定的值无效。EPERM 描述: 调用方无权执行该操作。

pthread_mutexattr_getprioceiling

pthread_mutex_setprioceiling

pthread_mutex_getprioceiling

pthread_mutexattr_setrobust_np

pthread_mutexattr_getrobust_np

demo

多核多线程的demo留待下面文章来记录。

你可能感兴趣的:(Android,c++,多线程)