精华内容
下载资源
问答
  • 该例程是参考FreeRTOS官方说明自己编写的代码,内部包含MDK工程源码,希望能帮助到初学FreeRTOS的学子。
  • 主要为大家详细介绍了C#多线程中如何运用互斥锁Mutex,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 多线程编程:互斥锁使用。 打包文件包含两个文件:c文件源代码、Makefile文件,运行环境在Ubuntu14.04下,使用自带的gcc编译器,同学们只需将文件夹复制到某一目录下之后在终端执行:1.“make”生成“test”可执行...
  • 而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起配合使用使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。...
  • Java互斥锁简单实例

    2020-09-03 13:27:19
    主要介绍了Java互斥锁,较为详细的分析了java互斥锁的概念与功能,并实例描述了java互斥锁的原理与使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
  • 自旋锁替代互斥锁使用场景

    千次阅读 2018-11-22 16:47:45
    自旋锁替代互斥锁使用场景

    自旋锁与互斥锁

    自旋锁和互斥锁是多线程程序中的重要概念。 它们被用来锁住一些共享资源, 以防止并发访问这些共享数据时可能导致的数据不一致问题。 但是它们的不同之处在哪里? 我们应该在什么时候用自旋锁代替互斥锁?

    理论分析

    从理论上说, 如果一个线程尝试加锁一个互斥锁的时候没有成功, 因为互斥锁已经被锁住了, 这个未获取锁的线程会休眠以使得其它线程可以马上运行。 这个线程会一直休眠, 直到持有锁的线程释放了互斥锁, 休眠的线程才会被唤醒。 如果一个线程尝试获得一个自旋锁的时候没有成功, 该线程会一直尝试加锁直到成功获取锁。 因此它不允许其它线程运行(当然, 操作系统会在该线程所在的时间片用完时, 强制切换到其它线程)。

    互斥锁的问题

    互斥锁存在的问题是, 线程的休眠和唤醒都是相当昂贵的操作, 它们需要大量的CPU指令, 因此需要花费一些时间。 如果互斥量仅仅被锁住很短的一段时间, 用来使线程休眠和唤醒线程的时间会比该线程睡眠的时间还长, 甚至有可能比不断在自旋锁上轮训的时间还长。自旋锁的问题是, 如果自旋锁被持有的时间过长, 其它尝试获取自旋锁的线程会一直轮训自旋锁的状态, 这将非常浪费CPU的执行时间, 这时候该线程睡眠会是一个更好的选择。

    自旋锁应用场景

    在单核/单CPU系统上使用自旋锁是没用的, 因为当线程尝试获取自旋锁不成功的时候会一直尝试, 这会一直占用CPU, 其它线程不可能运行, 因为其他线程不能运行, 这个锁也就不会被解锁。 换句话说, 在单核/单CPU的系统上,自旋锁除了浪费时间没有一点好处。 这时如果这个线程(记为A)可以休眠, 其它线程可以立即运行, 因为其它有可能解锁, 那么线程A可能在唤醒后继续执行。
    在多核/多CPU的系统上, 特别是大量的线程只会短时间的持有锁的时候, 在使线程睡眠和唤醒线程上浪费大量的时间, 也许会显著降低程序的运行性能。 使用自旋锁, 线程可以充分利用调度程序分配的时间片(经常阻塞很短的时间, 不用休眠, 然后马上继续它们的工作了), 以达到更高的处理能力和吞吐量。

    自旋锁实践

    因为程序员往往并不能事先知道哪种方案会更好(比如, 不知道运行环境的CPU核的数量), 操作系统也不知道一段指令是不是针对单核或者多核环境下做过优化, 所以大部分操作系统并不严格区分互斥锁和自旋锁。 实际上, 绝大部分现代的操作系统采用的是混合型互斥锁(hybrid mutexes)和混合型自旋锁(hybrid spinlocks)。 它们是什么意思呢?
    混合型互斥锁, 在多核系统上起初表现的像自旋锁一样, 如果一个线程不能获取互斥锁, 它不会马上被切换为休眠状态, 因为互斥量可能很快就被解锁, 所以这种机制会表现的像自旋锁一样。 只有在一段时间以后(或者尝试一定次数,或者其他指标)还不能获取锁, 它就会被切换为休眠状态。 如果运行在单核/单CPU上, 这种机制将不会自旋(就像上面解释的, 这种情况自旋没有什么好处)。
    混合型自旋锁, 起初表现的和正常自旋锁一样, 但是为了避免浪费大量的CPU时间, 会有一个折中的策略。 这种机制不会把线程切换到休眠态(既然想要使用自旋锁, 那么你并不希望这种情况发生), 也许会决定放弃这个线程的执行(马上放弃或者等一段时间)并允许其他线程运行, 这样提高了自旋锁被解锁的可能性(大多数情况, 线程之间的切换操作比使线程休眠而后唤醒它要昂贵, 尽管那不是很明显)。

    总结

    如果对选择哪种方案感到疑惑, 那就使用互斥锁吧, 并且大多数现代的操作系统都允许在获取锁的时候自旋一段时间(混合型互斥锁)。 只有在一定条件下使用自旋锁才可以提高性能, 事实上, 你现在在做的项目可能没有一个能在通过自旋锁提高性能。 也许你考虑使用你自己定义的”锁对象”, 它可以在内部使用互斥锁或者自旋锁(例如: 在创建锁对象时, 用哪种机制是可配置的), 刚开始在所有的地方都是用互斥锁, 如果你认为在有些地方用自旋锁确实可以提高性能, 你可以试试, 并且比较两种情况的结果(使用一些性能评测工具), 但一定要在单核和多核环境上测试之后再下结论(如果你的代码是夸平台的, 也要尽可能在不同的平台上测试下)。

    展开全文
  • 互斥锁与事件锁

    2018-02-26 10:00:55
    里面详细介绍了互斥锁与事件锁,内有DEMO,并介绍了事件锁的两种方式的对比
  • Linux互斥锁使用

    2020-08-28 23:12:09
    目录 互斥锁原理 1. 互斥锁原理 如上图所示:如果多个线程要访问...多线程编程是建议使用互斥锁,这样可以对公共区域的数据进行保护。互斥锁的缺点就是串行,数据访问的效率会有一定的降低。 2. 互斥锁的相关函数

    目录

    1. 互斥锁原理

    2. 互斥锁相关函数

    3. 互斥锁使用过程

    4. 互斥锁使用示例

    5. 死锁


    1. 互斥锁原理

    如上图所示:如果多个线程要访问一段共享资源的内存区域时,其中一个线程(如图中线程1)首先读取共享区域时,会在共享区域外设置一把互斥锁,其它线程阻塞在互斥锁处,线程1结束共享资源的访问后,会解锁该内存区域,此时其它的线程才可以继续访问共享资源的内存区域。本来多线程访问数据时是并行访问内存区域的,加上互斥锁后变为串行处理。

    多线程编程是建议使用互斥锁,这样可以对公共区域的数据进行保护。互斥锁的缺点就是串行,数据访问的效率会有一定的降低。

    2. 互斥锁相关函数

    1.创建互斥锁函数
    pthread_mutex_t mutex;
    
    2.初始化互斥锁函数:
    int pthread_mutex_init(pthread_mutex_t *restrict mutex, 
                           const pthread_mutexattr_t *restrict attr
                            ); 
        参数1:传出参数,调用是创建的互斥锁变量。
        参数2:传入参数,互斥锁属性,一般为NULL表示为默认属性
        这里的restrict关键字,表示指针指向的内容只能通过这个指针进行修改
        restrict关键字作用可以理解为:
    	    用来限定指针变量。被该关键字限定的指针变量所指向的内存操作,必须由本指针完成。
        
        初始化可以使用静态初始化和动态初始化,示例:
        pthread_mutex_t mutex;
    		1. pthread_mutex_init(&mutex, NULL);   			动态初始化。
    		2. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;	静态初始化。
    
    3.加锁
    int pthread_mutex_lock(pthread_mutex_t *mutex);
         参数:mutex
         没有上锁,当前线程会将这把锁上锁
         已经上锁,当前线程会阻塞在此
                  锁被打开之后,线程会解除阻塞
    
    4.尝试加锁
    int pthread_mutex_trylock(pthread_mutex_t *mutex);
          参数:mutex
          没有上锁:同上
          已经上锁,不阻塞返回
    
    5.解锁
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
    
    6.销毁一个互斥锁
    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    

    3. 互斥锁使用过程

    (1)创建互斥锁:pthread_mutex_t mutex;

    (2)初始化互斥锁: pthread_mutex_init(&mutex, NULL);

    (3)找到线程共同操作的共享资源

               加锁:prhread_mutex_lock(&mutex);     //如果共享区域已经上锁,会阻塞线程

                          pthread_mutex_trylock(&mutex);   //如果共享区域已经上锁,直接返回,不会阻塞。

    (4)访问内存区域

    (5)解锁:pthread_mutex_unlock(&mutex);

    (6)销毁:pthread_mutex_destory(&mutex);

     使用注意:

    尽量保证锁的粒度,越小越好,一般访问共享数据前加锁,访问结束立即解锁

            互斥锁,本质是结构体。 我们可以看成整数。 初值为 1。(pthread_mutex_init() 函数调用成功。)

            加锁: --操作, 阻塞线程。

            解锁: ++操作, 唤醒阻塞在锁上的线程。

            try锁:尝试加锁,成功--。失败,返回。同时设置错误号 EBUSY

    4. 互斥锁使用示例

    pthread_mutex.c:主线程建立两个子线程对全局变量进行++操作。

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <string.h>
    #include <pthread.h>
    
    
    #define MAX 10000
    // 全局变量
    int number;
    //创建一把互斥锁
    pthread_mutex_t mutex;
    
    
    // 线程A处理函数
    void* funcA_num(void* arg)
    {
        for(int i=0; i<MAX; ++i)
        {
            //访问全局变量之前加锁
            //如果mutex被锁上了,代码阻塞在当前位置
            pthread_mutex_lock(&mutex);
            int cur = number;
            cur++;
            number = cur;
            printf("Thread A, id = %lu, number = %d\n", pthread_self(), number);
            //解锁
            pthread_mutex_unlock(&mutex);
            usleep(10);
        }
     
        return NULL;
    }
    // 线程B处理函数 
    void* funcB_num(void* arg)
    {
        for(int i=0; i<MAX; ++i)
        {
            pthread_mutex_lock(&mutex);
            int cur = number;
            cur++;
            number = cur;
            printf("Thread B, id = %lu, number = %d\n", pthread_self(), number);
                    pthread_mutex_unlock(&mutex);
            usleep(10);
        }
     
        return NULL;
    }
    
    /*主函数创建两个线程,分别操作共享区域内存:全局变量number*/
    int main(int argc, const char* argv[])
    {
        pthread_t p1, p2;
            //初始化互斥锁
        pthread_mutex_init(&mutex,NULL);
     
        // 创建两个子线程
        pthread_create(&p1, NULL, funcA_num, NULL);
        pthread_create(&p2, NULL, funcB_num, NULL);
     
        // 阻塞,资源回收
        pthread_join(p1, NULL);
        pthread_join(p2, NULL);
     
            //释放互斥锁资源
        pthread_mutex_destroy(&mutex);
     
        return 0;
    }

    运行结果:AB两个线程逐个访问共享内存区域。

    5. 死锁

    程序运行是要避免死锁的情况。通常出现死锁的情况有两种:
           1.  对一个锁反复lock:对一个地方使用了两次锁,没有及时解锁

    2. 两个线程,各自持有一把锁,请求另一把锁,如下图所示:A,B两个线程访问AB两个共享数据区域时。

    解决方法:

            1. 让线程按照一定的顺序去访问共享资源

            2. 在访问的其他锁的时候,需要先将字节的锁解开

            3.trylock方式定义锁

    展开全文
  • 线程与互斥锁的应用

    2015-01-04 17:00:43
    两个线程,一个线程echo,一个线程cat来读取手机的imei
  • 互斥锁示例代码

    2015-06-14 22:40:50
    Linux系统编程——线程同步与互斥:互斥锁,相关教程链接如下: http://blog.csdn.net/tennysonsky/article/details/46494077
  • 使用mutex(互斥量、互斥锁)一般步骤: pthread_mutex_init 函数 初始化一个互斥锁(互斥量) —> 初值可看作1 int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr...

    对公共数据进行保护。所有线程【应该】在访问公共数据前先拿锁再访问。但,锁本身不具备强制性。

    在这里插入图片描述

    使用mutex(互斥量、互斥锁)一般步骤:

    pthread_mutex_init 函数

    初始化一个互斥锁(互斥量) —> 初值可看作1

    int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);1:传出参数,调用时应传 &mutex 
        	restrict 关键字:只用于限制指针,告诉编译器,所有修改该指针指向内存中内容的操作,只能通过本指针完成。不能通过除本指针以外的其他变量或指针修改 
    	参 2:互斥量属性。是一个传入参数,通常传NULL,选用默认属性(线程间共享)。 参APUE.12.4 同步属性 
    
    1. 静态初始化:如果互斥锁 mutex 是静态分配的(定义在全局,或加了 static 关键字修饰),可以直接使用宏进行初始化。e.g. pthead_mutex_t muetx = PTHREAD_MUTEX_INITIALIZER;
    2. 动态初始化:局部变量应采用动态初始化。e.g. pthread_mutex_init(&mutex, NULL)

    pthread_mutex_destroy 函数

    销毁一个互斥锁

    int pthread_mutex_destroy(pthread_mutex_t *mutex); 
    

    pthread_mutex_lock 函数

    加锁。可理解为将mutex–(或 -1),操作后mutex 的值为 0。

    int pthread_mutex_lock(pthread_mutex_t *mutex); 
    

    pthread_mutex_unlock 函数

    解锁。可理解为将mutex ++(或 +1),操作后mutex 的值为 1。

    cint pthread_mutex_unlock(pthread_mutex_t *mutex); 
    

    pthread_mutex_trylock 函数

    尝试加锁

    int pthread_mutex_trylock(pthread_mutex_t *mutex); 
    

    创建流程:

    pthread_mutex_t 类型。 
    
    1. pthread_mutex_t lock;  创建锁
    
    2  pthread_mutex_init; 初始化		
    
    3. pthread_mutex_lock;加锁		
    
    4. 访问共享数据(stdout)		
    
    5. pthrad_mutext_unlock();解锁		
    
    6. pthead_mutex_destroy;销毁锁
    

    加锁与解锁

    lock 尝试加锁,如果加锁不成功,线程阻塞,阻塞到持有该互斥量的其他线程解锁为止。
    unlock 主动解锁函数,同时将阻塞在该锁上的所有线程全部唤醒,至于哪个线程先被唤醒,取决于优先级、调度。默认:先阻塞、先唤醒。
    例如:T1 T2 T3 T4 使用一把 mutex 锁。T1 加锁成功,其他线程均阻塞,直至T1 解锁。T1 解锁后,T2 T3 T4 均被唤醒,并自动再次尝试加锁。

    注意事项:

    ​ 尽量保证锁的粒度, 越小越好。(访问共享数据前,加锁。访问结束【立即】解锁。)

    ​ 互斥锁,本质是结构体。 我们可以看成整数。 初值为 1。(pthread_mutex_init() 函数调用成功。)

    ​ 加锁: --操作, 阻塞线程。

    ​ 解锁: ++操作, 换醒阻塞在锁上的线程。

    ​ try锁:尝试加锁,成功–。失败,返回。同时设置错误号 EBUSY

    互斥锁demo

    #include<unistd.h>
    #include<string.h>
    #include<stdlib.h>
    #include<pthread.h>
    #include<stdio.h>
    
    pthread_mutex_t mutex;  //定义一把互斥锁
    
    void *tfn(void *arg){
    	srand(time(NULL));
    	while(1){
    		pthread_mutex_lock(&mutex);
    		printf("hello ");
    		sleep(rand()%3);
    		printf("world\n");
    		pthread_mutex_unlock(&mutex);
    		sleep(rand()%3);
    	}
    	return NULL;
    }
    
    int main(void){
    	pthread_t tid;
    	srand(time(NULL));
    	int ret=pthread_mutex_init(&mutex,NULL);  //初始化互斥锁
    	if(ret!=0){
    		fprintf(stderr,"mute init error:%s\n",sterror(ret));
    		exit(1);
    	}
    	pthread_create(&tid,NULL,tfn,NULL);
    	while(1){
    		pthread_mutex_lock(&mutex);
    		printf("HELL0 ");
    		sleep(rand()%3);
    		printf("WORLD\n");
    		pthread_mutex_unlock(&mutex);
    		sleep(rand()%3);
    	}
        pthread_join(tid,NULL);
    	pthread_mutex_destroy(&mutex); //销毁互斥锁
    	return 0;
    
    }
    
    展开全文
  • linux内核信号量和互斥锁使用

    千次阅读 2019-09-01 11:29:08
    信号量在创建时需要设置一个初始值,表示同时可以有几个任务可以访问该信号量保护的共享资源,初始值为 1 就变成互斥锁(Mutex),即同时只能有一个任务可以访问信号量保护的共享资源。 一个任务要想...

    信号量概念

    Linux 内核的信号量在概念和原理上与用户态的 System V 的 IPC 机制信号量是一样的,但是它绝不可能在内核之外使用,因此它与 System V 的 IPC 机制信号量毫不相干。
    信号量在创建时需要设置一个初始值,表示同时可以有几个任务可以访问该信号量保护的共享资源,初始值为 1 就变成互斥锁(Mutex),即同时只能有一个任务可以访问信号量保护的共享资源。
    一个任务要想访问共享资源,首先必须得到信号量,获取信号量的操作将把信号量的值减 1,若当前信号量的值为负数,表明无法获得信号量,该任务必须挂起在该信号量的等待队列等待该信号量可用;若当前信号量的值为非负数,表示可以获得信号量,因而可以立刻访问被该信号量保护的共享资源。
    当任务访问完被信号量保护的共享资源后,必须释放信号量,释放信号量通过把信号量的值加 1 实现,如果信号量的值为非正数,表明有任务等待当前信号量,因此它也唤醒所有等待该信号量的任务。

    内核信号量核心结构

    内核中使用 struct semaphore 结构来描述一个信号量,结构定义如下:

    struct semaphore {
    raw_spinlock_t lock;
    unsigned int count; //信号值,只要这个值为正数,则信号可用, 一般情况设置 0 或 1。
    struct list_head wait_list;
    };

    信号量相关 API

    DEFINE_SEMAPHORE (name)

    宏原型#define DEFINE_SEMAPHORE(name) \
    struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
    宏功能该宏声明一个信号量 name 并初始化它的值为 1,即声明一个互斥锁
    宏参数name: 要定义的信号量变量名
    所在头文件include\linux\semaphore.h
    宏定义文件include\linux\semaphore.h
    备注Linux3.5 内核出现 在 linux 2.6 中名字为 DECLARE_MUTEX(name)

    void sema_init(struct semaphore *sem, int val)

    宏(函数) 原型

    void sema_init(struct semaphore *sem, int val)

    宏功能该函数用于初始化一个互斥锁,即它把信号量 sem 的值设置为 1。
    宏参数sem: 要初始化的信号量的指针
    所在头文件include\linux\semaphore.h
    宏定义文件include\linux\semaphore.h
    备注 

    void sema_init (struct semaphore *sem, int val);

    宏原型void sema_init (struct semaphore *sem, int val);
    宏功能初始化设置信号量的初值,它设置信号量 sem 的值为 val
    宏参数sem: 要初始化的信号量的指针;
    val: 信号量的值
    所在头文件include\linux\semaphore.h
    宏定义文件include\linux\semaphore.h

    定义、初始化信号量相关 API:这是一个静态定义方式。 定义一个名字为 name,信号量值为 1 的信号量结构变量。
    示例:
    struct semaphore sem;
    sema_init(&sem, 1);
    以上两行等效:
    DEFINE_SEMAPHORE(sem);
     

    void down(struct semaphore *sem)

    函数原型void down(struct semaphore * sem);
    函数功能用于获得信号量 sem,它会导致睡眠,因此不能在中断上下文(包括 IRQ 上下文和 softirq 上
    下文)使用该函数。该函数将把 sem 的值减 1,如果信号量 sem 的值非负,就直接返回,否
    则调用者将被挂起,直到别的任务释放该信号量才能继续运行。
    函数参数sem: 要初始化获取的信号量的指针;
    函数返回值
    所在头文件include\linux\semaphore.h
    函数定义文件kernel\semaphore.c

    int down_timeout(struct semaphore *sem, long jiffies);
    sem: 信号量结构指针
    jiffies: 要设置超时时间,单位是时钟节拍。
    阻塞地请求一个信号量,如果信号量大于 0, 则可以马上返回, 否则休眠,直到有其他进程释放信号量
    (把信号量的 count 修改为大于 0 的值) 或超时时间到。
    这个函数效果和 down 函数很像,它也是不可中断的休眠。
     

    int down_interruptible(struct semaphore * sem);

    函数原型int down_interruptible(struct semaphore * sem);
    函数功能该函数功能与 down 类似,不同之处为, down 不会被信号(signal)打断,但 down_interruptible
    能被信号打断,因此该函数有返回值来区分是正常返回还是被信号中断,如果返回 0,表示
    获得信号量正常返回,如果被信号打断,返回-EINTR。
    函数参数sem: 要获取的信号量的指针;
    函数返回值0:得到信号量正常返回 ; 负数:被信号中断返回
    所在头文件include\linux\semaphore.h
    函数定义文件kernel\semaphore.c

    int down_trylock(struct semaphore * sem);

    函数原型int down_trylock(struct semaphore * sem);
    函数功能该函数试着获得信号量 sem,如果能够立刻获得,它就获得该信号量并返回 0,否则,表示
    不能获得信号量 sem,返回值为非 0 值。因此,它不会导致调用者睡眠,可以在中断上下文
    使用。
    函数参数sem: 要获取的信号量的指针;
    函数返回值0:得到信号量正常返回 ; 非 0:得不到信号量
    所在头文件include\linux\semaphore.h
    函数定义文件kernel\semaphore.c

    void up(struct semaphore * sem);

    函数原型void up(struct semaphore * sem);
    函数功能该函数释放信号量 sem,即把 sem 的值加 1,如果 sem 的值为非正数,表明有任务等待该信
    号量,因此唤醒这些等待者。
    函数参数sem: 要初释放的信号量的指针;
    函数返回值
    头文件include\linux\semaphore.h
    函数定义文件kernel\semaphore.c

    虽然信号量可以设置为大于 1 的值,但是信号量在绝大部分情况下作为互斥锁使用。

     


    简单信号量使用例子实现设备只能被一个进程打开:

    #include <linux/module.h> /* Needed by all modules */
    #include <linux/init.h> /* Needed for the module-macros */
    #include <linux/fs.h>
    #include <linux/miscdevice.h>
    #include <asm/atomic.h>
    #define LEDS_MAJOR 255
    #define DEVICE_NAME "miscdev_semaphore"
    
    DECLARE_MUTEX(lock); //定义一个互斥信号量,并初始化 1;
    
    static int first_miscdev_open(struct inode *pinode, struct file *pfile)
    {
    printk (KERN_EMERG "Linux miscdevice:%s is call\r\n",__FUNCTION__);
    
    /* 获取信号量 */
    if (!down_trylock(&lock))
    return 0;
    else
    return -EBUSY;
    }
    
    int first_miscdev_release (struct inode *inode, struct file *file)
    {
    printk (KERN_EMERG "Linux miscdevice:%s is call\r\n",__FUNCTION__);
    
    up(&lock); //释放信号量
    return 0;
    }
    static struct file_operations dev_fops =
    {
    .owner = THIS_MODULE,
    .open = first_miscdev_open,
    .release= first_miscdev_release,
    };
    static struct miscdevice misc =
    {
    .minor = LEDS_MAJOR,
    .name = DEVICE_NAME,
    .fops = &dev_fops,
    };
    /* 模块装载执行函数 */
    static int __init first_miscdev_init(void)
    {
    int ret;
    ret = misc_register(&misc); //注册混杂设备
    if(ret <0)
    printk (KERN_EMERG DEVICE_NAME"\t err\r\n");
    printk (KERN_EMERG DEVICE_NAME"\tinitialized\n");
    return ret;
    }
    
    /* 模块卸载执行函数 */
    static void __exit first_miscdev_exit(void)
    {
    misc_deregister(&misc);
    printk(KERN_EMERG "Goodbye,cruel world!, priority = 0\n");
    }
    module_init(first_miscdev_init);
    module_exit(first_miscdev_exit);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("XYD");
    MODULE_DESCRIPTION("This the samlpe drv_test");

    互斥信号量

    互斥信号量概念:

    互斥锁主要用于实现内核中的互斥访问功能。内核互斥锁是在原子 API 之上实现的,但这对于内核用户是不可见的。 在大部分场合中,对共享资源的访问,都是使用独占方式, 在这种情况下, 提供专门的互斥接口给编程者使用。 对它的访问必须遵循一些规则:同一时间只能有一个任务持有互斥锁,而且只有这个任务可以对互斥锁进行解锁。互斥锁不能进行递归锁定或解锁。一个互斥锁对象必须通过其 API 初始化,而不能使用 memset 或复制初始化。一个任务在持有互斥锁的时候是不能结束的。互斥锁所使用的内存区域是不能被释放的。使用中的互斥锁是不能被重新初始化的。并且互斥锁不能用于中断上下文。但是互斥锁比当前的内核信号量选项更快,并且更加紧凑,因此如果它们满足您的需求,那么它们将是您明智的选择。

    内核信号量核心结构

    内核中使用 struct mutex 结构来描述一个信号量,结构定义如下:
     

    struct mutex {
    /* 1: unlocked, 0: locked, negative: locked, possible waiters */
    atomic_t count;
    spinlock_t wait_lock;
    struct list_head wait_list;
    #if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
    struct task_struct *owner;
    #endif
    #ifdef CONFIG_DEBUG_MUTEXES
    const char *name;
    void *magic;
    #endif
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
    struct lockdep_map dep_map;
    #endif
    };

    关键成员说明:
    atomic_t count:
    指示互斥锁的状态:
    1--没有上锁,可以获得
    0--被锁定,不能获得
    负数--被锁定,且可能在该锁上有等待进程
    初始化时为没有上锁状态。


    spinlock_t wait_lock:
    等待获取互斥锁中使用的自旋锁。在获取互斥锁的过程中,操作会在自旋锁的保护中进行。初始化为为
    锁定, 用户一般无需关心。

    struct list_head wait_list:
    等待互斥锁的进程队列, 用户无需关心。

    互斥信号量相关 API

    DEFINE_MUTEX(mutexname)

    宏原型#define DEFINE_MUTEX(mutexname) \
    struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
    宏功能该宏声明一个互斥信号量 name 并初始化它
    宏参数name: 要定义的互斥信号量变量名
    所在头文件include\linux\mutex.h
    备注linux3.5出现

    mutex_init(mutex)

    宏原型# define mutex_init(mutex) \
    do { \
    static struct lock_class_key __key; \
    __mutex_init((mutex), #mutex, &__key); \
    } while (0)
    宏功能该宏初始化一个已经定义的互斥信号量, metex 传递的是指针
    宏参数mutex: 初始化的的互斥信号量指针
    所在头文件include\linux\mutex.h
    宏定义文件include\linux\mutex.h

    int mutex_is_locked(struct mutex *lock)

    宏原型int mutex_is_locked(struct mutex *lock)
    宏功能该函数检测互斥锁是否已经被锁定,
    宏参数lock: 互斥锁变量是指针
    返回值1 : 已经锁定 0: 没有锁定
    所在头文件include\linux\mutex.h

    mutex_lock(lock) 或 void mutex_lock(struct mutex *lock);

    宏(函数) 原型mutex_lock(lock)

    void mutex_lock(struct mutex *lock);
    宏功能该宏(函数) 获取互斥锁是否, 如没有得到会休眠,直接得到为止
    宏参数lock: 互斥锁变量是指针
    返回值
    所在头文件include\linux\mutex.h
    宏定义文件include\linux\mutex.h
    备注根据内核配置不同,该功能有有宏版本和函数版本

    mutex_lock_interruptible(lock) 或 int mutex_lock_interruptible(struct mutex *lock);

    宏原型#define mutex_lock_interruptible(lock) mutex_lock_interruptible_nested(lock, 0)

    int __must_check mutex_lock_interruptible(struct mutex *lock);
    宏功能该宏(函数)获取互斥锁是否, 如没有得到会休眠,直接得到为止, 但是可以被信号中断
    宏参数lock: 互斥锁变量是指针
    返回值成功获得锁返回 0, 被信号中断返回-EINIR
    所在头文件include\linux\mutex.h
    宏定义文件include\linux\mutex.h
    备注根据内核配置不同,该功能有有宏版本和函数版本

    int mutex_trylock(struct mutex *lock);

    宏原型int mutex_trylock(struct mutex *lock);
    宏功能该函数是获取互斥锁, 如没有得到不会休眠,马上返回
    宏参数lock: 互斥锁变量是指针
    返回值
    所在头文件include\linux\mutex.h
    宏定义文件include\linux\mutex.c
    备注根据内核配置不同,该功能有有宏版本和函数版本

    void mutex_unlock(struct mutex *lock);

    宏原型void mutex_unlock(struct mutex *lock);
    宏功能该函数是释放互斥锁
    宏参数lock: 互斥锁变量是指针
    返回值
    所在头文件include\linux\mutex.h
    宏定义文件include\linux\mutex.c

    互斥锁应用例子:

    /* chardev.c */
    #include <linux/module.h>       /* Needed by all modules */
    #include <linux/init.h>              /* Needed for the module-macros */
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <linux/device.h>       /* 自动创建设备文件 */
    #include <linux/miscdevice.h>
    #include <asm/io.h>                /*ioremap*/
    #include <asm/uaccess.h>       /*copy_from_user ,copy_to_user*/
    #include <linux/atomic.h>
    #include <linux/mutex.h>
    
    #include <linux/gpio.h>
    #include <mach/gpio.h>
    #include <plat/gpio-cfg.h>  /* s3c_gpio_cfgpin  S3C_GPIO_OUTPUT */
    static struct cdev *pcdev;
    static struct device *this_device = NULL;
    static struct class *leds_class = NULL;
    
    /* 是否开启 gpio_request 函数功能 */
    #define GPIO_REQUEST          1     //0 :关,非0 :开 
    
    static int led_gpios[] = {
      EXYNOS4X12_GPM4(0),
      EXYNOS4X12_GPM4(1),
      EXYNOS4X12_GPM4(2),
      EXYNOS4X12_GPM4(3),
    };
    
    #define LED_NUM     ARRAY_SIZE(led_gpios)
    #define   DEV_NAME   "myleds"
    unsigned int major  = 0;                    //主设备号
    unsigned int minor = 0;                   //次设备号
    
    unsigned int devnr = 0;                    //设备号
    char *chrdev_name = DEV_NAME;  //设备名
    module_param(major, int, S_IRUGO | S_IWUSR);
    module_param(minor, int, S_IRUGO | S_IWUSR);
    module_param(chrdev_name, charp, S_IRUGO | S_IWUSR);
    
    
    struct mutex lock;
    
    //打开设备时候执行的程序
    static int  chrdev_open(struct inode *pinode, struct file *pfile)
    {
       mutex_lock(&lock);
    
      printk(KERN_EMERG "line:%d,%s is call\n", __LINE__, __FUNCTION__);
      return 0;
    }
    
    //关闭设备时执行的程序
    static int chrdev_release(struct inode *pinode, struct file *pfile)
    {
       mutex_unlock(&lock);
      printk(KERN_EMERG "line:%d,%s is call\n", __LINE__, __FUNCTION__);
      return 0;
    }
    
    
    
    //读接口函数
    static ssize_t chrdev_read ( struct file *file,
                                 char __user *buf,
                                 size_t count,
                                 loff_t * f_pos )
    {
      char led_buffer[4] = {2, 2, 2, 2};
      int i = 0;
      //  printk ( KERN_EMERG "line:%d,%s is call\n", __LINE__, __FUNCTION__ );
    
      /* count ==0 ,则返回0,不是错误 */
      if ( !count ) {
        return 0;
      }
    
      /* 当前已经到文件末尾,不能再写,返回0,*/
      if ( count > LED_NUM ) {
        count =  LED_NUM;
      }
    
    
      /* 准备数据,0表示灭,1表示亮 */
      for (i = 0; i < LED_NUM; i++) {
        led_buffer[i] = !gpio_get_value(led_gpios[i]);
      }
    
      if ( copy_to_user ( buf, &led_buffer[0], count ) ) {
        return -EFAULT;
      }
    
      return count;
    }
    
    
    
    //写接口函数
    static ssize_t chrdev_write(struct file *pfile,
                                const char __user *user_buf,
                                size_t count,
                                loff_t *off)
    {
      int ret = 0;
      char buf[LED_NUM] = {0};
      int i = 0;
      // printk(KERN_EMERG "line:%d,%s is call\n", __LINE__, __FUNCTION__);
      //应用程序传递count=0下来,并不是错误,应该返回0
      if(count == 0) {
        return 0;
      }
    
      //因为板子只有4个灯,所以防止用户程序恶意破坏系统。
      if(count > LED_NUM) {
        count = LED_NUM;
      }
    
      //把用户空间传递下来的数据复制到内核空间的buf数组中
      ret = copy_from_user(buf, user_buf, count); //返回,成功是0,其他是失败
      if(ret) { //如果复制失败返回-1;
        return -EFAULT;
      }
    
      for(i = 0; i < count; i++) {
        if(buf[i] == 1)
          //                  GPM4DAT &= ~(1 << (0 + i));/* 亮 */
    
        {
          gpio_set_value(led_gpios[i], 0);
        }
    
        else if(buf[i] == 0)
          //                  rGPM4DAT |=  (1 << (0 + i));/* 灭 */
        {
          gpio_set_value(led_gpios[i], 1);
        }
    
      }
    
      count  = 1;
    
    
      return count;
    }
    
    
    
    //文件操作方法:
    static const  struct file_operations chrdev_fops = {
      .read      = chrdev_read,
      .write     = chrdev_write,
      .release  = chrdev_release,
      .open     = chrdev_open,
    };
    
    
    
    static int __init chrdev_init(void)
    {
    
      int ret = 0;
      int i;
    
      /* IO口配置代码 */
      for (i = 0; i < LED_NUM; i++) {
    #if GPIO_REQUEST
        ret = gpio_request(led_gpios[i], "LED");
        if (ret) {
          printk("%s: request GPIO %d for LED failed, ret = %d\n",
                 chrdev_name, led_gpios[i], ret);
          goto gpio_request_err;
        }
    #endif
    
        //s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);
        //gpio_set_value(led_gpios[i], 1);
        //gpio_direction_output等效于上面两条语句,
        gpio_direction_output(led_gpios[i], 1);
    
      }
    
      //分配cdev核心结构;
      pcdev = cdev_alloc();
      if (pcdev == NULL) {
        ret = -ENOMEM;
        printk(KERN_EMERG"cdev_alloc_err error\n");
        goto cdev_alloc_err;
      }
    
      //如果主设备号是0,则动态分配设备号
      if(!major) {
        ret  = alloc_chrdev_region(&devnr, minor, 1, chrdev_name);
        if(ret < 0) {
          printk(KERN_EMERG"alloc_chrdev_region error\n");
          goto devnr_requst_err;
        }
    
      } else {
    
        //合成设备号
        devnr =  MKDEV(major, minor);
    
        //静态注册设备号
        ret = register_chrdev_region(devnr, 1, chrdev_name);
        if(ret != 0) {
          printk(KERN_EMERG"register_chrdev_region error\n");
          goto devnr_requst_err;
        }
      }
    
      //cdev结构体初始化
      cdev_init(pcdev, &chrdev_fops);
    
      //注册字符设备
      ret = cdev_add(pcdev, devnr, 1);
      if ( ret < 0) {
        printk(KERN_EMERG"cdev_add error\n");
        goto cdev_add_err;
      }
    
      //输出字符设备主设备号和次设备号
      printk(KERN_EMERG "name:%s,major:%d,minor:%d\n",
             chrdev_name, MAJOR(devnr), MINOR(devnr));
    
      //创建一个类
      leds_class =   class_create(THIS_MODULE, "leds_class");
      if ( IS_ERR(leds_class) ) {
        ret = PTR_ERR(leds_class);
        printk(KERN_EMERG"class_create error\n");
        goto class_create_err;
      }
    
      //创建一个设备
      this_device = device_create(leds_class, NULL, devnr, NULL, "%s", chrdev_name);
      if ( IS_ERR(this_device) ) {
        ret = PTR_ERR(this_device);
        printk(KERN_EMERG"this_device error\n");
        goto device_create_err;
      }
    
      mutex_init(&lock);
      return 0;
    
    device_create_err:
      class_destroy(leds_class);
    class_create_err:
      unregister_chrdev(major, chrdev_name);
    cdev_add_err:
    devnr_requst_err:
      if (pcdev) {
        cdev_del(pcdev);
      }
      unregister_chrdev_region(devnr, 1);
    cdev_alloc_err:
    
    #if GPIO_REQUEST
    gpio_request_err:
      /* gpio 反向释放 */
      for ( --i ; i >= 0 ; i-- ) {
        gpio_free(led_gpios[i]);
      }
    #endif
    
      return ret;
    }
    
    static void  __exit chrdev_exit(void)
    {
      int i = 0;
      device_destroy(leds_class, devnr);
      class_destroy(leds_class);
    
      /* gpio 反向释放 */
      for (   ; i < 4 ; i++) {
        gpio_free(led_gpios[i]);
      }
    
      cdev_del(pcdev);
      unregister_chrdev_region(devnr, 1);
      printk(KERN_EMERG "Goodbye,chrdev\n");
    }
    module_init(chrdev_init);
    module_exit(chrdev_exit);
    
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_AUTHOR("learn");                //optional
    MODULE_DESCRIPTION("STUDY_MODULE"); //optional


     

    展开全文
  • Ruby 中使用 Redis 的分布式互斥锁。 支持阻塞和非阻塞语义。 这个想法来自。 概要 在下面的例子中,一次只有一个线程/进程/服务器可以进入锁定块。 RedisMutex . with_lock ( :your_lock_name ) do # do ...
  • 互斥锁使用不当导致线程阻塞

    千次阅读 2019-03-05 17:00:07
    互斥锁使用不当导致线程阻塞@TOC 写作目的 多线程之间通过消息队列进行进程间通信,在线程内部互斥锁使用不当,导致线程阻塞。花费了比较多的时间去定位,故整理下自己所犯的错误,也为后来阅读者起一个提示作用,...
  • 主要介绍了Java使用synchronized实现互斥锁功能,结合实例形式分析了Java使用synchronized互斥锁功能简单实现方法与操作技巧,需要的朋友可以参考下
  • 在学习操作系统时候,其中关于线程的同步有四种方式:互斥锁,条件变量,读写锁,信号量,互斥锁,读写锁和信号量,这些都比较容易理解,关于条件变量,就不太好理解了,其中条件变量还注明了必须与互斥锁一起使用,...
  • 目录互斥的理解使用场景使用方法使用原则互斥失败的例子 互斥的理解 一句话理解互斥: 等我完厕所,你再厕所。 什么是互斥?你我早起都要厕所,谁先抢到谁先,中途不被打扰。 伪代码如下: void 抢厕所(void...
  • 自旋锁互斥锁使用注意区别

    千次阅读 2018-07-12 14:17:12
    2.由于一直查询,所以自旋锁一直占用cpu,互斥锁不会,自旋锁导致cpu使用效率低3.自旋锁容易造成死锁 互斥锁和自旋锁的区别https://blog.csdn.net/susidian/article/details/510688581、自旋锁一直占用CPU,他在未...
  • 互斥锁(为了实现多个线程对同一共享资源的争管理) 在多任务操作系统中,同时运行的多个任务可能都需要使用同一种资源。这个过程有点类似于,多人共用一台打印机,为了使大家都能有序公正的使用这台打印机,肯定...
  • 主要介绍了简单的JavaScript互斥锁的相关资料,需要的朋友可以参考下
  • vxworks 下互斥锁

    2014-07-01 14:29:27
    讲述了vxworks 互斥锁的应用,由于资料较少,这还是比较难得的
  • 主要介绍了Python实现的多线程同步与互斥锁功能,涉及Python多线程及锁机制相关操作技巧,需要的朋友可以参考下
  • 互斥锁使用

    2020-11-27 13:34:53
    mutexpthread_mutex_t数据类型表示,在使用互斥锁前,必须先对它进行初始化。 静态分配的互斥锁: pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 动态分配互斥锁: pthread_mutex_t mutex; pthread_mutex_...
  • 最常用的就是互斥锁,当然还有很多种不同的锁,比如自旋锁、读写锁、乐观锁等,不同种类的锁自然适用于不同的场景。 如果选择了错误的锁,那么在一些高并发的场景下,可能会降低系统的性能,这样用户体验就会非常差...
  • 主要介绍了PHP程序中的文件锁、互斥锁、读写锁使用技巧解析,其中重点讲解了sync模块和pthreads模块中的使用实例,需要的朋友可以参考下
  • linux互斥锁使用方法

    千次阅读 2019-01-08 11:33:01
    互斥锁实际上就是为了防止一个线程在使用某一其他线程也能访问到的变量时,其他线程也去使用这个变量,导致变量值不可预测。 以上测试程序若注释掉有注释的三句话,也就是不使用互斥锁,则实验效果为 val在...
  • 自旋锁和互斥锁区别

    2020-07-18 05:33:26
    线程同步(Thread Synchronization)是并行编程中非常重要的通讯手段,其中最典型的应用就是Pthreads提供的机制(lock)来对多个线程之间共 享的临界区(Critical Section)进行保护(另一种常用的同步机制是barrier)。
  • FreeRTOS互斥锁

    千次阅读 2020-02-18 17:24:48
    目录 基本特性 本质 ...互斥锁用于互斥就像是一个令牌一样用于保护资源,当一个任务想要获取这个资源时,先要获得这个令牌,使用完资源后,必须还回令牌,允许其他的任务获得这个资源。 ...
  • 线程-互斥锁使用

    2020-07-18 17:24:22
    mutex互斥锁 2>锁的使用过程:任务访问临界资源前申请锁,访问完释放锁 二、函数介绍 1.互斥锁的初始化 方法1:动态方式创建互斥锁 #include<pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 183,209
精华内容 73,283
关键字:

互斥锁怎么用