Linux系统编程之线程互斥锁的使用方法

一、Linux上线程开发互斥锁概要

互斥量(mutex)从本质上来说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后,释放互斥量上的锁。 对互斥量进行加锁后,任何其它试图在再次对互斥量加锁的进行会被阻塞直到当前线程释放该互斥量上的锁。如果释放互斥锁时,有多个线程阻塞,则所有在该互斥锁的线程都会变成可运行状态,第一个变成可运行状态的线程可以对互斥量加锁,其它线程将会看到互斥锁依然被锁住,只能等待它从新变成可用。在这种方式下,每次只有一个线程可以向前运行。

在设计时需要规定所有的线程必须遵守相同的数据访问原则。只有这样,互斥机制才能正常工作。操作系统并不会做数据访问的串行化。如果允许其中的某个线程在没有得到锁的情况下也可以访问共享资源,那么即使其它的线程在使用共享资源前都获取了锁,也还是会出现数据不一致的问题。

互斥量变量使用 pthread_mutex_t 的数据类型表示。在使用互斥变量前必须对它进行初始化,可以把它置为常量 PTHREAD_MUTEX_INITALIZER(只对静态分配的互斥量),也可以通过调用 pthread_mutex_init 函数进行初始化。如果动态地分配互斥量(比如通过调用malloc函数),那么在释放内存前需要调用 pthread_mutex_destroy

二、创建及销毁互斥锁

对锁的操作

#include <pthread.h>
// 动态初始化
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
// 销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
// 返回:若成功返回0,否则返回错误编号

2.1 示例:主线程等待两个线程退出,1线程和2线程打印信息

不加锁的程序:

//demo5
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

int g_data=0;

void* fun1(void *arg)
{
        printf("t1:%ld thread is create\n", (unsigned long)pthread_self());
        printf("t1: %d\n", *((int*)arg));
}

void* fun2(void *arg)
{
        printf("t2:%ld thread is create\n", (unsigned long)pthread_self());
        printf("t2: %d\n", *((int*)arg));
}

int main()
{

        //int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
        int ret;
        int param = 100;
        pthread_t t1;
        pthread_t t2;

        //                       线程属性 线程函数 线程函数参数
        ret = pthread_create(&t1, NULL, fun1, (void*)&param);
        if(ret == 0){
                printf("main:create t1 success\n");
        } else {
                perror("why t1 fail");
        }

        ret = pthread_create(&t2, NULL, fun2, (void*)&param);
        if(ret == 0){
                printf("main:create t1 success\n");
        } else {
                perror("why t2 fail");
        }

        printf("main:%ld\n", (unsigned long)pthread_self());//打印主线程ID


        pthread_join(t1, NULL);//等待线程结束,防止进程结束,线程还未执行完毕
        pthread_join(t2, NULL);//等待线程结束,防止进程结束,线程还未执行完毕

        return 0;
}

在这里插入图片描述
从运行结果看出:执行顺序不一样,每次都不是固定的顺序。

思考:那我们能不能让 t1先运行,t2运行,然后 main 最后运行?能不能保证能!得加钱!啊不,得加锁

想让t1先运行,需要先定义一个锁。被锁锁住的代码都叫做互斥量

加锁步骤:

  1. 创建一个锁,锁的名字叫做mutex,是一个全局变量,线程1和线程2都能看到这把锁。 在这里插入图片描述

  2. 在创建线程之前对锁进行初始化 在这里插入图片描述

  3. 程序退出后,要销毁这把锁
    在这里插入图片描述

  4. 想让t1先运行,对t1进行上锁:先上锁,打印两句话,然后解锁在这里插入图片描述

  5. 同理,t2也是在这里插入图片描述

运行结果:
编译 -> 运行 -> 结果:都是t1先执行(由于没加延时,可能存在偶然性,每次恰好是t1先执行完例程,因为计算机算力太强了,程序很小)
在这里插入图片描述

修改t1:让多执行几次(几百几千次也行,可以大一点,或者选择加延时函数),测试互斥锁。
在这里插入图片描述

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

互斥量就是一把锁,被锁锁住的代码都叫做互斥量。对锁操作有加锁操作 pthread_mutex_lock() 和解锁操作 pthread_mutex_unlock 。在加锁和解锁之间的代码,称之为共享资源。

可见,对于共享资源的使用,只有锁被释放后,其它依赖共享资源的线程才能得以继续执行。

三、互斥量的初始化问题

可以使用宏进行初始化,属于是静态初始化。

在使用互斥变量前必须进行初始化,可以置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量);也可以通过调用pthread_mutex_init、pthread_cond_init函数进行初始化。如果动态地分配互斥量,那么在释放内存前需要调用pthread_mutex_destroy。

动态初始化:
pthread_mutex_t mutex;
主函数中必须:
pthread_mutex_init(&mutex, NULL); //dynamic init

使用宏进行初始化(静态初始化):
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // static init

  • 19
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值