C-线程之互斥锁、动态锁、静态锁

我们为什么要使用互斥锁呢?首先,我们需要了解临界资源(也就是共享资源)的概念。

临界资源:

临界资源通常需要被保护,以确保在任何给定时间只有一个线程或进程能够访问它,这就是所谓的临界区。在临界区内,对临界资源的访问需要通过同步机制来控制,比如使用互斥锁、信号量、条件变量等。通过这些同步机制,可以确保对临界资源的访问是原子的,不会出现竞态条件或数据竞争等问题,从而保证程序的正确性和稳定性。
比如写文件,只能由一个线程写,假若多个线程同时对文件操作那肯定会乱。也可以看这个up讲的线程锁-互斥锁这个例子,你就会更进一步明白为什么要使用互斥锁。

那谈到互斥锁,如何来创建呢?有静态方式动态方式两种,分别称为静态锁动态锁

静态锁

初始化方式

静态锁是在编译时刻进行初始化的,通过宏或特殊的语法来完成。在 POSIX 线程库中,可以使用 PTHREAD_MUTEX_INITIALIZER 宏来静态初始化互斥锁。

生命周期

静态锁的生命周期与程序的生命周期相同,它在程序启动时被初始化,在程序结束时被销毁(也就说不用写销毁代码进行销毁,这点不同于动态锁,后面的代码展示到了这点)。因此,静态锁在整个程序的执行过程中都是可用的。

 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

这行代码声明了一个名为 mutex 的互斥锁,并使用了 PTHREAD_MUTEX_INITIALIZER 进行了初始化。

适合使用静态锁的情况:

  • 互斥锁对象的数量是固定的
    如果程序中的互斥锁数量是固定的,并且在编译时就能够确定,那么静态锁会更方便,因为它们在编译时就被初始化了。
  • 需要简化代码
    静态锁的初始化是通过宏或特殊的语法完成的,相对于动态锁,使用静态锁可能能够简化代码。

静态锁使用例程

#include <stdio.h>
#include <unistd.h>
#include <string.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

FILE *fp;
void *func2(void *arg){
    pthread_detach(pthread_self()); //分离线程,自动回收。线程分离三种方式中的其中一种
    printf("This func2 thread\n");
    
    char str[]="I write func2 line\n";
    char c;
    int i=0;
    while(1){
        pthread_mutex_lock(&mutex);
        while(i<strlen(str))
        {
            c = str[i];
            fputc(c,fp);
            usleep(1);
            i++;
        }
        pthread_mutex_unlock(&mutex);
        i=0;
        usleep(1);
    }
    pthread_exit("func2 exit");
}

void *func(void *arg){
    pthread_detach(pthread_self());
    printf("This is func1 thread\n");
    char str[]="You read func1 thread\n";
    char c;
    int i=0;
    while(1){
        pthread_mutex_lock(&mutex);
        while(i<strlen(str))
        {
            c = str[i];
            fputc(c,fp);
            i++;
            usleep(1);
        }
        pthread_mutex_unlock(&mutex);
        i=0;
        usleep(1);
    }
    pthread_exit("func1 exit");
}

int main(){
    pthread_t tid,tid2;
    void *retv;
    int i;
    fp = fopen("1.txt","a+");
    if(fp==NULL){
        perror("fopen");
        return 0;
    }

    pthread_create(&tid,NULL,func,NULL);
    pthread_create(&tid2,NULL,func2,NULL);
    while(1){    
        sleep(1);
    } 
}

对上述代码稍作解释:
pthread_mutex_lock(&mutex)在两个函数中都用到了,我是这么理解的pthread_mutex_lock(&mutex)在哪个函数中使用就保护哪个函数的临界区。换句话说,只有当一个线程成功地获得了互斥锁 mutex,它才能执行临界区内的代码。其他线程如果尝试获得 mutex 的锁,但该锁已被另一个线程持有,则它们将被阻塞,直到该锁被释放。因此,可以在不同的函数中分别使用 pthread_mutex_lock(&mutex) 来保护这些函数各自的临界区。这样可以确保同一时间只有一个线程能够访问每个函数的临界区,从而实现线程安全。

需要注意的是,pthread_mutex_lock(&mutex)和pthread_mutex_unlock(&mutex)必须成对使用

动态锁

初始化方式

动态锁是在运行时刻进行初始化的,需要调用专门的初始化函数(比如 pthread_mutex_init)来创建和初始化锁。

生命周期

动态锁的生命周期可以通过初始化销毁函数来控制,它们在需要时创建,在不再需要时销毁。这种灵活性使得动态锁更适合于某些特定场景,比如动态创建的线程或者需要动态管理资源的情况。

适合使用动态锁的情况:

  • 需要动态创建锁:
    如果程序需要在运行时动态地创建锁,并且锁的数量或属性可能会根据程序运行时的条件而变化,那么动态锁会更适合。

  • 需要更灵活的管理资源:
    动态锁的生命周期可以根据需要进行控制,这使得程序能够更灵活地管理资源,避免资源的浪费或者不足。

动态锁使用例程

#include <pthread.h>
#include <stdio.h>

void *client_handler(void *arg) {
    pthread_mutex_t *mutex = (pthread_mutex_t *)arg;
    pthread_mutex_lock(mutex);
    // Critical section
    printf("Processing request...\n");
    pthread_mutex_unlock(mutex);
    return NULL;
}

int main() {
    int num_threads = 10; // Number of threads can vary
    pthread_t threads[num_threads];
    pthread_mutex_t mutex;

    // Initialize dynamic mutex
    pthread_mutex_init(&mutex, NULL);
    // Start client threads
    for (int i = 0; i < num_threads; i++) {
        pthread_create(&threads[i], NULL, client_handler, (void *)&mutex);
    }
    // Join threads
    for (int i = 0; i < num_threads; i++) {
        pthread_join(threads[i], NULL);
    }
    // Destroy mutex after use
    pthread_mutex_destroy(&mutex);

    return 0;
}

这是一个简单的动态锁使用。

在使用过程中,最好只使用一把锁,从而避免死锁。

静态锁和动态锁的概念比较基础和简单。该篇是目前对学到的东西做的笔记,是个人的一些心得体会。参考了GPT及一些网络资源,后面还有学习心得会继续补充。新手,如有建议或不对的,欢迎讨论一下哦。

  • 35
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值