Linux互斥锁及其应用

简介: Linux互斥锁及其应用

互斥锁


作用: 防止多线程对同一个数据同时进行操作


在线程实际运行过程中,我们经常需要多个线程保持同步。这时可以用互斥锁来

完成任务。


1.1锁的创建


互斥锁可以动态或静态的被创建


可以用宏PTHREAD_MUTEX_INITIALIZER来静态的初始化锁,采用这种方式比较容易理解


互斥锁是pthread_mutex_t的结构体,而这个宏是一个结构常量,如下可以完成静态的初始化锁:


pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;


动态创建是通过pthread_mutex_init函数实现,函数原型如下:


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


其中:


mutex:所需创建的锁;


attr:创建锁的属性。一般默认为NULL,


分为以下几个属性:


PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性;


PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争;


PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁;


PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争;


1.2 锁操作


对锁的操作主要包括加锁pthread_mutex_lock()、解锁pthread_mutex_unlock()

和测试加锁pthread_mutex_trylock()三个,函数原型如下:


int pthread_mutex_lock(pthread_mutex_t*mutex); 
int pthread_mutex_unlock(pthread_mutex_t *mutex); 
int pthread_mutex_trylock(pthread_mutex_t *mutex); 


pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待。


1.3 锁销毁


创建的互斥锁在不使用的时候需要消耗,不然会造成系统资源的流失,其函数原

型如下:


int pthread_mutexattr_destroy(pthread_mutex_t *mutex);


1.4互斥锁属性


使用互斥锁(互斥)可以使线程按顺序执行。通常,互斥锁通过确保一次只有一个线程执行代码的临界段来同步多个线程。互斥锁还可以保护单线程代码。


要更改缺省的互斥锁属性,可以对属性对象进行声明和初始化。通常,互斥锁属性会设置在应用程序开头的某个位置,以便可以快速查找和轻松修改。


初始化互斥锁属性对象


使用pthread_mutexattr_init(3C)可以将与互斥锁对象相关联的属性初始化为其缺省值。在执行过程中,线程系统会为每个属性对象分配存储空间。


pthread_mutexattr_init 语法


int pthread_mutexattr_init(pthread_mutexattr_t *mattr); 
#include <pthread.h> 
pthread_mutexattr_t mattr; 
int ret;/* initialize an attribute to default value */ 
ret = pthread_mutexattr_init(&mattr);


调用此函数时,pthread 属性的缺省值为 PTHREAD_PROCESS_PRIVATE。 该值表示可以在进程内使用经过初始化的互斥锁。


mattr 的类型为 opaque,其中包含一个由系统分配的属性对象。mattr 范围可能的值为 PTHREAD_PROCESS_PRIVATE 和 PTHREAD_PROCESS_SHARED。

PTHREAD_PROCESS_PRIVATE 是缺省值。


对于互斥锁属性对象,必须首先通过调用 pthread_mutexattr_destroy(3C) 将其销毁,才能重新初始化该对象。pthread_mutexattr_init() 调用会导致分配类型为 opaque 的对象。如果未销毁该对象,则会导致内存泄漏。


pthread_mutexattr_init 返回值


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


ENOMEM 描述:内存不足,无法初始化互斥锁属性对象。


销毁互斥锁属性对象


pthread_mutexattr_destroy(3C)可用来取消分配用于维护


pthread_mutexattr_init() 所创建的属性对象的存储空间。


pthread_mutexattr_destroy 语法


int pthread_mutexattr_destroy(pthread_mutexattr_t *mattr) 
#include <pthread.h> 
pthread_mutexattr_t mattr; 
int ret;/* destroy an attribute */ ret = pthread_mutexattr_destroy(&mattr); 


pthread_mutexattr_destroy 返回值


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


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


案例


/*************************************************************************
    > File Name: pthread.c
    > Author: 杨永利
    > Mail: 1795018360@qq.com 
    > Created Time: 2020年07月27日 星期一 20时42分45秒
 ************************************************************************/
#include <stdio.h>
#include <pthread.h>
void * thread_addi(void *arg)
{
    int* tmp=arg;
    int i=0;
    for(i;i<1000000;i++)
    {
        ++(*tmp);
        //printf("%d\n",i);
    }
    return NULL;
}
int main(int argc, char* argv[]){
    int i=0;
    printf("我的初始化i是:%d\n",i);
    long int s=(long int)&i;
    pthread_t pid;
    pthread_create(&pid,NULL,thread_addi,&i);
    int j=0;
    for(j;j<1000000;j++)
    {
        i++;
        //printf("%d\n",i);
    }
    void *v;
    pthread_join(pid,v);
    printf("%s\n",(char*)v);
    printf("i最终的值为:%d\n",i);
    return 0;
}


遇到问题


运行之后我们会发现i的最终结果里2000000差很多,这是为什么呢???


这是因为两个线程的时间片分配时产生了干扰,当数特别小时干扰是看不到的,但是当进行的操作增大时,系统在给两个线程分配时间片时就会产生干扰,也就是上个例子中和最终加不满的问题。


那么 我们就在加数操作之后来加一句输出延缓时间,看看能不能加到2000000,



我们可以看到这已经很接近2000000了,但是还是无法加到最后


那么怎样改进呢?这就用到了我们的互斥锁。


解决方案


在加数操作上加上加锁和解锁操作。


1.在循环外加锁解锁



结果



2.在循环内加锁解锁(效率最高)


/*************************************************************************
    > File Name: pthread.c
    > Author: 杨永利
    > Mail: 1795018360@qq.com 
    > Created Time: 2020年07月27日 星期一 20时42分45秒
 ************************************************************************/
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex;
void * thread_addi(void *arg)
{
    int* tmp=arg;
    int i=0;
    for(i;i<1000000;i++)
    {
        pthread_mutex_lock(&mutex);
        ++(*tmp);
        //printf("%d\n",i);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}
int main(int argc, char* argv[]){
    int i=0;
    printf("我的初始化i是:%d\n",i);
    long int s=(long int)&i;
    int err=pthread_mutex_init(&mutex,NULL);
    if(err!=0)
    {
        printf("锁创建失败\n");
        return -1;
    }
    pthread_t pid;
    pthread_create(&pid,NULL,thread_addi,&i);
    int j=0;
    for(j;j<1000000;j++)
    {
        pthread_mutex_lock(&mutex);
        i++;
        //printf("%d\n",i);
        pthread_mutex_unlock(&mutex);
    }
    void *v;
    pthread_join(pid,v);
    printf("%s\n",(char*)v);
    printf("i最终的值为:%d\n",i);
    return 0;
}


相关文章
|
8天前
|
机器学习/深度学习 安全 Linux
Linux 主要应用领域的归纳
服务器领域 Linux在服务器领域的应用是其最为广泛和成熟的领域之一。由于其开源、稳定、高效和安全的特性,Linux成为许多企业服务器的首选操作系统。 Web服务器:Linux是Web服务器的理想选择,因为它支持Apache、Nginx等流行的Web服务器软件,这些软件在Linux上运行稳定且性能卓越。Linux服务器可以高效地处理大量并发请求,提供快速、可靠的Web服务。 数据库服务器:Linux也广泛用于数据库服务器,如MySQL、PostgreSQL和Oracle等数据库管理系统在Linux上运行良好。Linux的稳定性和安全性使得它成为存储和管理敏感数据的理想平台。 邮件服务器:Lin
29 5
|
2月前
|
监控 算法 Linux
Linux内核锁机制深度剖析与实践优化####
本文作为一篇技术性文章,深入探讨了Linux操作系统内核中锁机制的工作原理、类型及其在并发控制中的应用,旨在为开发者提供关于如何有效利用这些工具来提升系统性能和稳定性的见解。不同于常规摘要的概述性质,本文将直接通过具体案例分析,展示在不同场景下选择合适的锁策略对于解决竞争条件、死锁问题的重要性,以及如何根据实际需求调整锁的粒度以达到最佳效果,为读者呈现一份实用性强的实践指南。 ####
|
3月前
|
算法 Linux 开发者
Linux内核中的锁机制:保障并发控制的艺术####
本文深入探讨了Linux操作系统内核中实现的多种锁机制,包括自旋锁、互斥锁、读写锁等,旨在揭示这些同步原语如何高效地解决资源竞争问题,保证系统的稳定性和性能。通过分析不同锁机制的工作原理及应用场景,本文为开发者提供了在高并发环境下进行有效并发控制的实用指南。 ####
|
3月前
|
缓存 Linux 开发者
Linux内核中的并发控制机制:深入理解与应用####
【10月更文挑战第21天】 本文旨在为读者提供一个全面的指南,探讨Linux操作系统中用于实现多线程和进程间同步的关键技术——并发控制机制。通过剖析互斥锁、自旋锁、读写锁等核心概念及其在实际场景中的应用,本文将帮助开发者更好地理解和运用这些工具来构建高效且稳定的应用程序。 ####
70 5
|
3月前
|
Linux 数据库
Linux内核中的锁机制:保障并发操作的数据一致性####
【10月更文挑战第29天】 在多线程编程中,确保数据一致性和防止竞争条件是至关重要的。本文将深入探讨Linux操作系统中实现的几种关键锁机制,包括自旋锁、互斥锁和读写锁等。通过分析这些锁的设计原理和使用场景,帮助读者理解如何在实际应用中选择合适的锁机制以优化系统性能和稳定性。 ####
90 6
|
3月前
|
存储 安全 关系型数据库
Linux系统在服务器领域的应用与优势###
本文深入探讨了Linux操作系统在服务器领域的广泛应用及其显著优势。通过分析其开源性、安全性、稳定性和高效性,揭示了为何Linux成为众多企业和开发者的首选服务器操作系统。文章还列举了Linux在服务器管理、性能优化和社区支持等方面的具体优势,为读者提供了全面而深入的理解。 ###
|
4月前
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解
|
6月前
|
Unix Linux Ruby
在windows和linux上高效快捷地发布Dash应用
在windows和linux上高效快捷地发布Dash应用
286 4
|
6月前
|
Linux iOS开发 开发者
跨平台开发不再难:.NET Core如何让你的应用在Windows、Linux、macOS上自如游走?
【8月更文挑战第28天】本文提供了一份详尽的.NET跨平台开发指南,涵盖.NET Core简介、环境配置、项目结构、代码编写、依赖管理、构建与测试、部署及容器化等多个方面,帮助开发者掌握关键技术与最佳实践,充分利用.NET Core实现高效、便捷的跨平台应用开发与部署。
663 3
|
6月前
|
存储 Linux 开发工具
【Azure App Service】本地Git部署Python Flask应用上云(Azure App Service For Linux)关键错误
【Azure App Service】本地Git部署Python Flask应用上云(Azure App Service For Linux)关键错误