在 C 语言中使用互斥锁

Jinku Hu 2023年10月12日 C C Mutex
在 C 语言中使用互斥锁

本文将介绍几种在 C 语言中使用互斥锁的方法。

使用 pthread_mutex_t 类型和 pthread_mutex_lock 函数来守护代码的关键部分

线程共享地址空间,这意味着对全局变量等共享数据的修改必须同步,否则,将出现不正确的程序行为。请注意,下面的代码用 pthread_create 调用创建了 4 个额外的线程,并传递 func3 作为它们执行的起点。func3 在 10000 次迭代 for 循环中逐一修改全局变量 shared。因此,如果四个线程分别将 shared 的值递增 10000,程序应该输出 40000。

如果执行下面的代码,结果将是某个随机整数,但不是 40000。这种行为一般被归为竞赛条件,意味着给定的线程在访问共享变量时没有相互协商即同步。即,往往当它们执行循环交错时,对共享变量的访问和存储达到不一致,最后得出错误的和。

多个线程修改内存中同一个对象的代码部分称为关键部分。一般来说,关键部分应该用某种类型的锁来保护,迫使其他线程等到当前线程完成执行,并确保它们都能得到正确的增量值。Mutex 是其中一种锁类型,可以利用它来保护关键部分,就像 func3 中的这个 for 循环一样。

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

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

int shared = 0;

void* func3(void* param) {
  printf("Incrementing the shared variable...\n");
  for (int i = 0; i < 10000; ++i) {
    shared += 1;
  }
  return 0;
}

int main() {
  pthread_t threads[NUM_THREADS];

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_create(&threads[i], NULL, func3, NULL);
  }

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_join(threads[i], NULL);
  }

  printf("%d\n", shared);
  exit(EXIT_SUCCESS);
}

输出:

Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
30384

在这种情况下,我们将利用 POSIX 线程库及其内置的 pthread_mutex_t 类型。pthread_mutex_t 类型变量通常被声明为 static 存储持续时间。互斥锁只能在使用前应该只初始化一次。当互斥锁被声明为 static 时,应该使用 PTHREAD_MUTEX_INITIALIZER 宏来初始化它。当互斥锁被初始化后,线程就可以相应地使用 pthread_mutex_lockpthread_mutex_unlock 函数。pthread_mutex_lock 锁定作为唯一参数传递的 mutex 对象。如果互斥锁已经被锁定,调用线程会被阻塞,直到互斥锁变得可用。应该调用 pthread_mutex_unlock 来解锁互斥锁。如果有线程在同一个互斥锁上等待,则由调度策略决定哪个线程获得对象锁。最后,我们对四个线程中的每一个线程都调用 pthread_join,并打印出整数-shared,在这种情况下,它应该有正确的值存储。

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

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

int shared = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* func3(void* param) {
  pthread_mutex_lock(&mutex);
  printf("Incrementing the shared variable...\n");
  for (int i = 0; i < 10000; ++i) {
    shared += 1;
  }
  pthread_mutex_unlock(&mutex);
  return 0;
}

int main() {
  pthread_t threads[NUM_THREADS];

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_create(&threads[i], NULL, func3, NULL);
  }

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_join(threads[i], NULL);
  }

  printf("%d\n", shared);
  exit(EXIT_SUCCESS);
}

输出:

Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
40000
Enjoying our tutorials? Subscribe to DelftStack on YouTube to support us in creating more high-quality video guides. Subscribe
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 创始人。Jinku 在机器人和汽车行业工作了8多年。他在自动测试、远程测试及从耐久性测试中创建报告时磨练了自己的编程技能。他拥有电气/电子工程背景,但他也扩展了自己的兴趣到嵌入式电子、嵌入式编程以及前端和后端编程。

LinkedIn Facebook