专栏首页null的专栏Linux C 编程——互斥锁mutex

Linux C 编程——互斥锁mutex

1、多线程的问题引入

多线程的最大的特点是资源的共享,但是,当多个线程同时去操作(同时去改变)一个临界资源时,会破坏临界资源。如利用多线程同时写一个文件:

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

const char filename[] = "hello";

void* thread(void *id){

        int num = *(int *)id;

        // 写文件的操作
        FILE *fp = fopen(filename, "a+");
        int start = *((int *)id);
        int end = start + 1;
        setbuf(fp, NULL);// 设置缓冲区的大小
        fprintf(stdout, "%d\n", start);
        for (int i = (start * 10); i < (end * 10); i ++){
                fprintf(fp, "%d\t", i);
        }
        fprintf(fp, "\n");
        fclose(fp);

        return NULL;
}

int main(){
        int num_thread = 5;
        pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread);
        int * id = (int *)malloc(sizeof(int) * num_thread);

        for (int i = 0; i < num_thread; i++){
                id[i] = i;
                if (pthread_create(&pt[i], NULL, thread, &id[i]) != 0){
                        printf("thread create failed!\n");
                        return 1;
                }
        }
        for (int i = 0; i < num_thread; i++){
                pthread_join(pt[i], NULL);
        }

        // 释放资源
        free(pt);
        free(id);
        return 0;
}

执行以上的代码,我们会发现,得到的结果是混乱的,出现上述的最主要的原因是,我们在编写多线程代码的过程中,每一个线程都尝试去写同一个文件,这样便出现了上述的问题,这便是共享资源的同步问题,在Linux编程中,线程同步的处理方法包括:信号量,互斥锁和条件变量。

2、互斥锁

互斥锁是通过锁的机制来实现线程间的同步问题。互斥锁的基本流程为:

  • 初始化一个互斥锁:pthread_mutex_init()函数
  • 加锁:pthread_mutex_lock()函数或者pthread_mutex_trylock()函数
  • 对共享资源的操作
  • 解锁:pthread_mutex_unlock()函数
  • 注销互斥锁:pthread_mutex_destory()函数

其中,在加锁过程中,pthread_mutex_lock()函数和pthread_mutex_trylock()函数的过程略有不同:

  • 当使用pthread_mutex_lock()函数进行加锁时,若此时已经被锁,则尝试加锁的线程会被阻塞,直到互斥锁被其他线程释放,当pthread_mutex_lock()函数有返回值时,说明加锁成功;
  • 而使用pthread_mutex_trylock()函数进行加锁时,若此时已经被锁,则会返回EBUSY的错误码。

同时,解锁的过程中,也需要满足两个条件:

  • 解锁前,互斥锁必须处于锁定状态;
  • 必须由加锁的线程进行解锁。

当互斥锁使用完成后,必须进行清除。

有了以上的准备,我们重新实现上述的多线程写操作,其实现代码如下所示:

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

pthread_mutex_t mutex;

const char filename[] = "hello";

void* thread(void *id){

        int num = *(int *)id;
        // 加锁

        if (pthread_mutex_lock(&mutex) != 0){
                fprintf(stdout, "lock error!\n");
        }
        // 写文件的操作
        FILE *fp = fopen(filename, "a+");
        int start = *((int *)id);
        int end = start + 1;
        setbuf(fp, NULL);// 设置缓冲区的大小
        fprintf(stdout, "%d\n", start);
        for (int i = (start * 10); i < (end * 10); i ++){
                fprintf(fp, "%d\t", i);
        }
        fprintf(fp, "\n");
        fclose(fp);

        // 解锁
        pthread_mutex_unlock(&mutex);

        return NULL;
}

int main(){
        int num_thread = 5;
        pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread);
        int * id = (int *)malloc(sizeof(int) * num_thread);

        // 初始化互斥锁
        if (pthread_mutex_init(&mutex, NULL) != 0){
                // 互斥锁初始化失败
                free(pt);
                free(id);
                return 1;
        }

        for (int i = 0; i < num_thread; i++){
                id[i] = i;
                if (pthread_create(&pt[i], NULL, thread, &id[i]) != 0){
                        printf("thread create failed!\n");
                        return 1;
                }
        }
        for (int i = 0; i < num_thread; i++){
                pthread_join(pt[i], NULL);
        }
        pthread_mutex_destroy(&mutex);

        // 释放资源
        free(pt);
        free(id);
        return 0;
}

最终的结果为:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Linux C 编程——多线程

    线程是计算机中独立运行的最小单位,运行时占用很少的系统资源。与多进程相比,多进程具有多进程不具备的一些优点,其最重要的是:对于多线程来说,其能够比多进程更加节省...

    zhaozhiyong
  • Linux C 编程——多线程

    线程是计算机中独立运行的最小单位,运行时占用很少的系统资源。与多进程相比,多进程具有多进程不具备的一些优点,其最重要的是:对于多线程来说,其能够比多进程更加节省...

    zhaozhiyong
  • 数据结构和算法——动态规划

    一、动态规划的思想     动态规划(dynamic programming)是一种算法设计的思想,主要是将一个问题划分成几个更小的问题,并对这样更小的问题进行...

    zhaozhiyong
  • MD5加密原理解析及OC版原理实现 原

          MD5算法是Hash算法的一种,叫做讯息摘要演算法。所谓摘要,从字面意思理解,是指内容的大概。在MD5算法中,这个摘要是指将任意数据映射成一个128...

    珲少
  • BZOJ2388: 旅行规划(分块 凸包)

    attack
  • BZOJ1898: [Zjoi2005]Swamp 沼泽鳄鱼(矩阵快速幂)

    attack
  • 图片操作系列 —(2)手势旋转图片

    在上次的文章:图片操作系列 —(1)手势缩放图片功能中,我们已经学会了如何用手势来对图片进行缩放。这次我们继续来看第二个操作,那就是如何用手势来旋转图片。

    青蛙要fly
  • HihoCoder#1279 : Rikka with Sequence(dp 枚举子集 二进制 神仙题)

    首先最裸的dp应该比较好想,设\(f[i][j][k]\)表示前\(i\)个数选出来的数异或和为\(j\),按位与和为\(k\)的方案数

    attack
  • View的事件体系

    2.MotionEvent 手指触摸屏幕后的一系列事件,包括ACTION_DOWN,ACTION_MOVE,ACTION_UP

    提莫队长
  • 洛谷P1251 餐巾计划问题(最小费用最大流)

    从$S$向$i'$连边$(p, INF)$,表示每天早上可以以$p$的费用无限提供餐巾

    attack

扫码关注云+社区

领取腾讯云代金券