• 线程同步方式---1 互斥锁


    概述:

      互斥锁可能是最简单的锁机制了。也是一个阻塞锁。

    函数API:

    1.1:用宏常量初始化:

    1 pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

    1.2:用函数初始化:

    1 #include <pthread.h>
    2 
    3 int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

    2.设置互斥量属性

    1 #include <pthread.h>
    2 
    3 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);

    attr:互斥量的属性结构指针

    type:PTHREAD_MUTEX_NORMAL(默认属性),PTHREAD_MUTEX_ERRORCHECK(会进行错误检查,速度比较慢),PTHREAD_MUTEX_RECURSIVE(递归锁)。对于递归锁,同一个线程对一个递归锁加锁多次,会有一个锁计数器,解锁的时候也需要解锁这个次数才能释放该互斥量。

    3.加锁与解锁

    1 #include <pthread.h>
    2 
    3 int pthread_mutex_lock(pthread_mutex_t *mutex);
    4 int pthread_mutex_trylock(pthread_mutex_t *mutex);
    5 int pthread_mutex_unlock(pthread_mutex_t *mutex);

    参数都是互斥量指针。pthread_mutex_lock()得不到锁会阻塞,int pthread_mutex_trylock()得不到锁会立即返回,并返回EBUSY错误。

    还有一个pthread_mutex_timedlock()会根据时间来等待加锁,如果这段时间得不到锁会返回ETIMEDOUT错误!

    1 #include <pthread.h>
    2 #include <time.h>
    3 
    4 int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);

    4.销毁互斥量

    1 #include <pthread.h>
    2 
    3 int pthread_mutex_destroy(pthread_mutex_t *mutex);

    mutex:创建的互斥量指针

    三.简单例子                                            

    写个简单的例子,主线程消费,子线程生产,并模拟使用过程中可能遇到的缺点

    复制代码
     1 /**
     2  * @file pthread_mutex.c
     3  */
     4 
     5 #include <stdio.h>
     6 #include <stdlib.h>
     7 #include <string.h>
     8 #include <unistd.h>
     9 #include <pthread.h>
    10 
    11 /* 定义互斥量 */
    12 pthread_mutex_t mtx;
    13 /* 互斥量属性 */
    14 pthread_mutexattr_t mtx_attr;
    15 /* 全局资源 */
    16 int money;
    17 
    18 void err_exit(const char *err_msg)
    19 {
    20     printf("error:%s
    ", err_msg);
    21     exit(1);
    22 }
    23 
    24 /* 线程函数 */
    25 void *thread_fun(void *arg)
    26 {
    27     while (1)
    28     {
    29         /* 加锁 */
    30         pthread_mutex_lock(&mtx);
    31 
    32         printf("子线程进入临界区查看money
    ");
    33         if (money == 0)
    34         {
    35             money += 200;
    36             printf("子线程:money = %d
    ", money);
    37         }
    38 
    39         /* 解锁 */
    40         pthread_mutex_unlock(&mtx);
    41 
    42         sleep(1);
    43     }
    44 
    45     return NULL;
    46 }
    47 
    48 int main(void)
    49 {
    50     pthread_t tid;
    51 
    52     /* 初始化互斥量属性 */
    53     if (pthread_mutexattr_init(&mtx_attr) == -1)
    54         err_exit("pthread_mutexattr_init()");
    55 
    56     /* 设置互斥量属性 */
    57     if (pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_NORMAL) == -1)
    58         err_exit("pthread_mutexattr_settype()");
    59 
    60     /* 初始化互斥量 */
    61     if (pthread_mutex_init(&mtx, &mtx_attr) == -1)
    62         err_exit("pthread_mutex_init()");
    63 
    64     /* 创建一个线程 */
    65     if (pthread_create(&tid, NULL, thread_fun, NULL)== -1)
    66         err_exit("pthread_create()");
    67 
    68     money = 1000;
    69     while (1)
    70     {
    71         /* 加锁 */
    72         pthread_mutex_lock(&mtx);
    73 
    74         if (money > 0)
    75         {
    76             money -= 100;
    77             printf("主线程:money = %d
    ", money);
    78         }
    79 
    80         /* 解锁 */
    81         pthread_mutex_unlock(&mtx);
    82 
    83         sleep(1);
    84     }
    85 
    86     return 0;
    87 }
    复制代码

    主线程和子线程都对money的操作进行了互斥量保护。68行,初始化money是1000,主线程每次消耗100,子线程只有到money是0是才会生产。sleep(1)防止独占cpu,也方便打印信息。编译运行:

    可以看到这里有个非常浪费资源的问题:主线程消耗money的时候,子线程它不知道什么时候才消耗完,每次内核调度到它时,它都进入临界区加锁互斥量,然后查看money,再解锁。这无意义的操作,简直是极大的浪费!有什么办法可以解决这个问题呢?它有一个好伙伴,叫条件变量

    四.死锁                                                  

    假设:当线程1获取锁1,再获取锁2后才能进入临界区1,线程2获取锁2,再获取锁1才能进入临界区2。某个时刻,线程1获取了锁1,再去获取锁2的时候发现锁2已经被线程2锁住了,而线程2获取锁2后,发现锁1被线程1锁住了。这样2个线程谁也不让谁,都进不了自己的临界区,就产生了死锁现象!一般遇到这种情况常见的解决办法是:规定统一的加锁顺序。线程1和线程2都按照先锁1,再锁2。还一种就是使用pthread_mutex_trylock(),如果该函数返回EBUSY错误,就释放这个线程的所有锁,不过效率有点低。

    转自:http://www.cnblogs.com/yuuyuu/p/5143881.html

  • 相关阅读:
    【python cookbook】替换字符串中的子串(使用Template)
    python 学习sys
    【python cookbook】 替换字符串中的子串
    Python文件读写
    【python cookbook】python过滤字符串中不属于指定集合的字符
    【python cookbook】改变多行文本字符串的缩进
    python字符编码
    【python cookbook】python访问子字符串
    【python cookbook】python 控制大小写
    过关了
  • 原文地址:https://www.cnblogs.com/luntai/p/6668699.html
Copyright © 2020-2023  润新知