精华内容
下载资源
问答
  • 互斥锁的使用
    2022-06-11 18:13:19

    1. 互斥锁lock

    定义:
    private static readonly object m_objLock = new object();
     
    使用:
    lock (m_objLock)
    {
      // todo
    }
    作用:将会锁住代码块的内容,并阻止其他线程进入该代码块,直到该代码块运行完成,释放该锁。

    注意:定义的锁对象应该是:私有+静态+只读+引用类型的对象,这样可以防止外部改变锁对象。

    2. 互斥锁Monitor

    定义:
    private static readonly object m_objLock = new object();
    使用:
    Monitor.Enter(m_objLock);
    //todo
    Monitor.Exit(m_objLock);
    作用:将会锁住代码块的内容,并阻止其他线程进入该代码块,直到该代码块运行完成,释放该锁。

    注意:注意:定义的锁对象应该是:私有+静态+只读+引用类型的对象,这样可以防止外部改变锁对象。

    Monitor有TryEnter的功能,可以防止出现死锁的问题,lock没有。

    3. 互斥锁Mutex

    定义:
    private static readonly Mutex mutex = new Mutex();
    使用:
    mutex.WaitOne();
    //todo
    mutex.ReleaseMutex();
    作用:将会锁住代码块的内容,并阻止其他线程进入该代码块,直到该代码块运行完成,释放该锁。

    注意:注意:定义的锁对象应该是:私有+静态+只读+引用类型的对象,这样可以防止外部改变锁对象。

    Mutex本身是可以系统级别的,所以是可以跨越进程的。

    更多相关内容
  • 多线程编程:互斥锁使用。 打包文件包含两个文件:c文件源代码、Makefile文件,运行环境在Ubuntu14.04下,使用自带的gcc编译器,同学们只需将文件夹复制到某一目录下之后在终端执行:1.“make”生成“test”可执行...
  • 下面小编就为大家带来一篇浅谈互斥锁为什么还要和条件变量配合使用。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 主要介绍了Java编程中的互斥锁,信号量和多线程等待机制实例详解,简单介绍了互斥锁和信号量的区别,需要的朋友可以了解下。
  • 主要介绍了Java使用synchronized实现互斥锁功能,结合实例形式分析了Java使用synchronized互斥锁功能简单实现方法与操作技巧,需要的朋友可以参考下
  • 在做多线程开发时,互斥锁是必不可少的。但c语言不像c++11有标准的线程库,在各种编译器支持的平台都可以使用。而且跨平台开发中,在业务逻辑里写不同平台的兼容代码,容易造成过多的冗余,以及代码结构过于复杂的...
  • 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


     

    展开全文
  • Java互斥锁简单实例

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

    千次阅读 2020-11-27 13:34:53
    mutex用pthread_mutex_t数据类型表示,在使用互斥锁前,必须先对它进行初始化。 静态分配的互斥锁: pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 动态分配互斥锁: pthread_mutex_t mutex; pthread_mutex_...

    1、初始化互斥锁

    mutex用pthread_mutex_t数据类型表示,在使用互斥锁前,必须先对它进行初始化。

    静态分配的互斥锁:
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

    动态分配互斥锁:
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex,NULL);

    销毁互斥锁:
    在所有使用过互斥锁的线程都不再需要使用时候,应调用pthread_mutex_destroy销毁互斥锁。

    #include<pthread.h>
    int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
    
    功能:初始化一个互斥锁。
    
    参数:
    mutex:互斥锁地址。
    attr:互斥锁的属性,NULL为默认的属性。
    
    返回值:
    成功:返回 0
    失败:返回非 0
    

    2、互斥锁上锁:

    互斥锁上锁1

    #include<pthread.h>
    int pthread_mutex_lock(pthread_mutex_t *mutex);
    
    功能:对互斥锁上锁,若已经上锁,则调用者一直阻塞到互斥锁解锁  
    
    参数:
    mutex:互斥锁地址。
    
    返回值:
    成功:返回 0
    失败:返回非 0
    

    互斥锁上锁2

    #include<pthread.h>
    int pthread_mutex_trylock(pthread_mutex_t *mutex);
    
    功能:对互斥锁上锁,若已经上锁,则上锁失败,函数立即返回。
    
    参数:
    mutex:互斥锁地址。
    
    返回值:
    成功:返回 0
    失败:返回非 0
    

    一般情况下在互斥锁上锁的时候用的是pthread_mutex_lock这个函数。

    3、互斥锁解锁:

    #include<pthread.h>
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
    
    功能:对指定的互斥锁解锁。
    
    参数: 
    mutex:互斥锁地址。
    
    返回值:
    成功:返回 0
    失败:返回非 0
    

    4、销毁互斥锁:

    #include<pthread.h>
    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    
    功能:销毁指定的一个互斥锁。
    
    参数:
    mutex:互斥锁地址。
    
    返回值:
    成功:返回 0
    失败:返回非 0 
    

    5、案例代码:

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<pthread.h>
    
    //通过互斥锁解决线程间互斥问题
    
    int money = 10000;
    
    //第一步:创建互斥锁(由于两个线程操作同一个互斥锁,所以定义在全局更加方便一点)
    pthread_mutex_t mymutex;
    
    void *pthread_fun1(void *arg)
    {
            int get,yu,shiji;
            get = 10000;
    
            //第三步:对共享资源的操作进行上锁
            pthread_mutex_lock(&mymutex);
    
            printf("张三正在查询余额……\n");
            sleep(1);
            yu =money;
    
            printf("张三正在取钱……\n");
            sleep(1);
            if(get > yu)
            {
                    shiji = 0;
            }
    
            else
            {
                    shiji = get;
                    yu = yu - get;
                    money = yu;
            }
    
            printf("张三想取%d元,实际取了%d元,余额为%d元\n",get,shiji,yu);
    
            //第四步:当共享资源的操作执行完毕后,对互斥锁执行解锁操作
            pthread_mutex_unlock(&mymutex);
    
            pthread_exit(NULL);
    
    }
    void *pthread_fun2(void *arg)
    {
            int get,yu,shiji;
            get = 10000;
    
            //第三步:对共享资源的操作进行上锁
            pthread_mutex_lock(&mymutex);
    
            printf("李四正在查询余额……\n");
            sleep(1);
            yu =money;
    
            printf("李四正在取钱……\n");
            sleep(1);
            if(get > yu)
            {
                    shiji = 0;
            }
    
            else
            {
                    shiji = get;
                    yu = yu - get;
                    money = yu;
            }
    
            printf("李四想取%d元,实际取了%d元,余额为%d元\n",get,shiji,yu);
    
            //第四步:当共享资源的操作执行完毕后,对互斥锁执行解锁操作
            pthread_mutex_unlock(&mymutex);
    
            pthread_exit(NULL);
    
    }
    
    int main(int argc,char const *argv[])
    
    {
    
            //第二步:初始化操作
            pthread_mutex_init(&mymutex,NULL);
    
            pthread_t thread1,thread2;
    
            if(pthread_create(&thread1,NULL,pthread_fun1,NULL) != 0)
            {
                    perror("fail to pthread_create");
                    exit(1);
            }
    
            if(pthread_create(&thread2,NULL,pthread_fun2,NULL) != 0)
            {
                    perror("fail to pthread_create");
                    exit(1);
            }
    
            pthread_join(thread1,NULL);
            pthread_join(thread2,NULL);
    
            //第五步:当互斥锁使用完毕后,要销毁
            pthread_mutex_destroy(&mymutex);
    
            return 0;
    }
    
    

    运行结果:
    在这里插入图片描述

    展开全文
  • 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方式定义锁

    展开全文
  • 自旋锁替代互斥锁使用场景

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

    2021-10-03 15:30:16
    app可快速进行应用无需烦的创建
  • 互斥锁与事件锁

    2018-02-26 10:00:55
    里面详细介绍了互斥锁与事件锁,内有DEMO,并介绍了事件锁的两种方式的对比
  • 本文不对自旋锁和互斥锁的概念做阐述,重点分析它们之间的区别和自旋锁的使用场景。 自旋锁和互斥锁的区别 a. 互斥锁加锁失败后,线程会释放 CPU,给其他线程;自旋锁加锁失败后,线程会忙等待,直到它拿到锁; b. ...
  • 互斥锁使用不当导致线程阻塞

    千次阅读 2019-03-05 17:00:07
    互斥锁使用不当导致线程阻塞@TOC 写作目的 多线程之间通过消息队列进行进程间通信,在线程内部互斥锁使用不当,导致线程阻塞。花费了比较多的时间去定位,故整理下自己所犯的错误,也为后来阅读者起一个提示作用,...
  • C++ 线程同步之互斥锁

    千次阅读 2022-06-19 15:10:59
    进行多线程编程,如果多个线程需要对同一块内存进行操作,比如:同时读、同时写、同时读写,对于后两种情况来说,如果不做任何的人为干涉就会出现各种各样的错误...除了使用 lock() 还可以使用 try_lock() 获取互斥锁
  • 使用互斥锁和共享内存实现的非阻塞FIFO,另外代码中有包含信号量的实现。个人测试稳定,有一些注释,一起学习。如有问题,欢迎讨论。
  • Mysql 中互斥锁使用

    2021-01-19 03:45:44
    本文介绍如在在多线程mysql代码开发中使用互斥锁。mysql自己对c++的mutex又进行了一次封装,封装的代码可以在include/mysql/psi/mysql_thread.h 中找到。下面大概地介绍下如何使用互斥锁。锁的生命周期大体为: 初始...
  • JAVA互斥锁

    2021-11-22 23:48:37
    * 互斥锁 * 当多个代码片被synchronized块修饰后,这些同步块的同步监听器对象又是同一个时 * 这些代码片端就是互斥的,多个线程不能同时在这些方法中运行 * @author ckx * */ public class SyncDemo4 { ...
  • 本文实例讲述了Python多线程操作之互斥锁、递归锁、信号量、事件。分享给大家供大家参考,具体如下: 互斥锁: 为什么要有互斥锁:由于多线程是并行的,如果某一线程取出了某一个数据将要进行操作,但它还没有那么...
  • 【Linux】多线程--互斥锁

    千次阅读 多人点赞 2022-05-12 08:57:27
    文章目录前言基础概念互斥量mutex多线程模拟抢票(没加锁情况)为何多线程访问临界资源是不安全互斥锁相关接口多线程模拟抢票(有加锁)互斥锁实现的基本原理 前言 为什么线程需要同步和互斥的操作? 因为线程引入...
  • Go互斥锁(Mutex)

    千次阅读 2022-03-21 21:36:25
    其中 state 表示当前互斥锁的状态,而 sema 是用于控制锁状态的信号量。 type Mutex struct { state int32 sema uint32 } 上述两个加起来只占 8 字节空间的结构体表示了 Go 语言中的互斥锁。 状态 互斥锁的状态...
  • 文章目录1 互斥锁2 实时互斥锁 重要:本系列文章内容摘自<Linux内核深度解析>...尽管可以把二值信号量当作互斥锁使用,但是内核单独实现了互斥锁。互斥锁的定义如下: include/linux/mutex.h struct mutex { at
  • MFC多线程互斥锁使用

    千次阅读 2019-10-04 23:14:12
    MFC多线程互斥锁使用 本例演示在MFC中使用多线程。第一部分实现多线程的开启、暂停、继续、注销(见上一篇文章MFC多线程的开启、暂停、继续和注销)。第二部分实现两个线程互斥锁使用。 演示系统为Win10,平台为...
  • 文章目录为什么会有线程安全问题互斥锁的引入互斥锁使用函数接口例子:抢票系统死锁的概念 为什么会有线程安全问题 我们知道,多线程编程时,创建出来的线程对应同一个虚拟地址空间,即拥有相同的数据,假设多个...
  • Linux C 互斥锁使用

    万次阅读 多人点赞 2019-06-13 14:45:22
    互斥锁的作用 保护共享数据: 在并发机制的情况下,有时候会有多个线程同时访问同一片数据,为了保护数据操作的准确性就需要通过加锁来进行保护。 保持操作互斥: 可能一个程序会有多个操作,但是同一个时间只能有...
  • 互斥锁使用过程及应用场景)

    千次阅读 2020-02-24 12:02:44
    互斥锁使用流程 定义互斥锁变量 pthread_mutex_t:互斥锁变量的类型 例:pthread_mutex_t mutex 初始化互斥锁变量 int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr); muter:...
  • C++ 互斥锁源码

    2017-09-01 11:33:02
    ConsoleApp_Mutex,C++互斥锁源码cpp,可在VC++6.0或VS下直接编译运行,演示结果,控制台程序,ConsoleApp_Mutex,C++互斥锁源码cpp,可在VC++6.0或VS下直接编译运行,演示结果,控制台程序,
  • 互斥锁pthread_mutex_t 在linux中,互斥锁的出现是为了限制多个线程同时对临界资源区进行访问。通过互斥锁对临界资源区进行保护,只有拥有锁的线程才可以访问临界区,没有的锁的线程如果要访问临界区则需要等到锁的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 212,912
精华内容 85,164
关键字:

互斥锁的使用