[学习] C语言编程中线程安全的实现方法(示例)

🧵C语言编程中线程安全的实现方法

在多线程编程中,线程安全(Thread Safety) 是一个非常重要的概念。当多个线程同时访问共享资源时,如果没有合理的同步机制,就可能导致数据竞争、死锁甚至程序崩溃。

本文将详细介绍在 C语言 中如何实现线程安全的几种主要方式,并提供可以实际运行的代码示例。


🔹 一、什么是线程安全?

线程安全是指:当多个线程并发访问某个函数或对象时,其行为仍然正确,不会因为并发访问而产生错误结果。


🔹 二、C语言中线程安全的实现方式

在C语言中,最常用的线程库是 POSIX Threads(pthread)。我们主要使用以下机制来实现线程安全:

  1. 互斥锁(Mutex)
  2. 读写锁(Read-Write Lock)
  3. 条件变量(Condition Variable)
  4. 原子操作(Atomic Operations)
  5. 线程局部存储(Thread Local Storage, TLS)

下面我们逐一介绍每种方法,并给出完整示例代码。


🔸 方法一:互斥锁(Mutex)

互斥锁是最基本也是最常用的同步机制。它可以保证同一时间只有一个线程能访问共享资源。

✅ 示例:用互斥锁保护计数器

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

int counter = 0;
pthread_mutex_t lock; // 定义互斥锁

void* increment_counter(void* arg) {
    for (int i = 0; i < 100000; ++i) {
        pthread_mutex_lock(&lock); // 加锁
        counter++;
        pthread_mutex_unlock(&lock); // 解锁
    }
    return NULL;
}

int main() {
    pthread_t t1, t2;

    // 初始化互斥锁
    pthread_mutex_init(&lock, NULL);

    // 创建两个线程
    pthread_create(&t1, NULL, increment_counter, NULL);
    pthread_create(&t2, NULL, increment_counter, NULL);

    // 等待线程结束
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    // 销毁互斥锁
    pthread_mutex_destroy(&lock);

    printf("Final counter value: %d\n", counter); // 应为 200000
    return 0;
}

📌 编译命令:

gcc -o mutex_example mutex_example.c -lpthread

🔸 方法二:读写锁(Read-Write Lock)

适用于读多写少的场景。允许多个线程同时读取资源,但只允许一个线程写入。

✅ 示例:读写锁保护共享结构体

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

typedef struct {
    char data[128];
} SharedData;

SharedData shared;
pthread_rwlock_t rwlock; // 定义读写锁

void* reader(void* arg) {
    for (int i = 0; i < 5; ++i) {
        pthread_rwlock_rdlock(&rwlock);
        printf("Reader: %s\n", shared.data);
        pthread_rwlock_unlock(&rwlock);
        sleep(1);
    }
    return NULL;
}

void* writer(void* arg) {
    const char* messages[] = {"Hello", "World", "Thread", "Safety", "Example"};
    for (int i = 0; i < 5; ++i) {
        pthread_rwlock_wrlock(&rwlock);
        strcpy(shared.data, messages[i]);
        printf("Writer: Updated to '%s'\n", shared.data);
        pthread_rwlock_unlock(&rwlock);
        sleep(2);
    }
    return NULL;
}

int main() {
    pthread_t r1, r2, w1;

    // 初始化读写锁
    pthread_rwlock_init(&rwlock, NULL);

    // 初始化共享数据
    strcpy(shared.data, "Initial");

    // 创建线程
    pthread_create(&r1, NULL, reader, NULL);
    pthread_create(&r2, NULL, reader, NULL);
    pthread_create(&w1, NULL, writer, NULL);

    // 等待所有线程完成
    pthread_join(r1, NULL);
    pthread_join(r2, NULL);
    pthread_join(w1, NULL);

    // 销毁锁
    pthread_rwlock_destroy(&rwlock);

    return 0;
}

📌 编译命令:

gcc -o rwlock_example rwlock_example.c -lpthread

🔸 方法三:条件变量(Condition Variable)

用于线程间的通信,常与互斥锁配合使用,等待某个条件成立后再继续执行。

✅ 示例:生产者-消费者模型

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

#define MAX_ITEMS 5

int buffer = -1;
int count = 0;
pthread_mutex_t mutex;
pthread_cond_t not_empty, not_full;

void* producer(void* arg) {
    for (int i = 0; i < 10; ++i) {
        pthread_mutex_lock(&mutex);
        while (count == MAX_ITEMS) {
            pthread_cond_wait(&not_full, &mutex);
        }
        buffer = i;
        count++;
        printf("Produced: %d\n", i);
        pthread_cond_signal(&not_empty);
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
    return NULL;
}

void* consumer(void* arg) {
    for (int i = 0; i < 10; ++i) {
        pthread_mutex_lock(&mutex);
        while (count == 0) {
            pthread_cond_wait(&not_empty, &mutex);
        }
        int item = buffer;
        count--;
        printf("Consumed: %d\n", item);
        pthread_cond_signal(&not_full);
        pthread_mutex_unlock(&mutex);
        sleep(2);
    }
    return NULL;
}

int main() {
    pthread_t prod, cons;

    // 初始化锁和条件变量
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&not_empty, NULL);
    pthread_cond_init(&not_full, NULL);

    // 创建线程
    pthread_create(&prod, NULL, producer, NULL);
    pthread_create(&cons, NULL, consumer, NULL);

    // 等待线程结束
    pthread_join(prod, NULL);
    pthread_join(cons, NULL);

    // 清理资源
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&not_empty);
    pthread_cond_destroy(&not_full);

    return 0;
}

📌 编译命令:

gcc -o condvar_example condvar_example.c -lpthread

🔸 方法四:原子操作(Atomic Operations)

适用于对某些变量进行不可中断的操作,如递增、比较交换等。

注意:C11标准引入了 _Atomic 类型和 <stdatomic.h> 头文件。

✅ 示例:使用原子变量实现计数器

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

_Atomic int atomic_counter = 0;

void* inc_atomic(void* arg) {
    for (int i = 0; i < 100000; ++i) {
        atomic_fetch_add(&atomic_counter, 1);
    }
    return NULL;
}

int main() {
    pthread_t t1, t2;

    pthread_create(&t1, NULL, inc_atomic, NULL);
    pthread_create(&t2, NULL, inc_atomic, NULL);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    printf("Atomic counter final value: %d\n", atomic_counter); // 应为 200000
    return 0;
}

📌 编译命令:

gcc -o atomic_example atomic_example.c -lpthread -std=c11

🔸 方法五:线程局部存储(TLS)

每个线程拥有独立的变量副本,避免共享带来的竞争问题。

✅ 示例:使用 __thread 关键字(GCC扩展)

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

__thread int tls_counter = 0; // 每个线程独立的计数器

void* thread_func(void* arg) {
    for (int i = 0; i < 5; ++i) {
        tls_counter++;
        printf("Thread %ld: tls_counter = %d\n", pthread_self(), tls_counter);
        sleep(1);
    }
    return NULL;
}

int main() {
    pthread_t t1, t2;

    pthread_create(&t1, NULL, thread_func, NULL);
    pthread_create(&t2, NULL, thread_func, NULL);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    return 0;
}

📌 编译命令:

gcc -o tls_example tls_example.c -lpthread

🔹 总结对比表

方法特点使用场景
互斥锁简单易用,粒度粗写操作频繁
读写锁支持并行读读多写少
条件变量配合互斥锁使用,支持等待通知生产者-消费者、状态等待
原子操作轻量级,无需锁单个变量的简单操作
线程局部存储线程独享变量日志、缓存、线程私有数据

🔹 小贴士

  • 合理选择同步机制,避免过度加锁导致性能下降。
  • 使用 RAII 或宏封装锁操作,减少死锁风险。
  • 对于高性能场景,可以考虑无锁队列、CAS算法等高级技术。

🔁 结语

线程安全是编写健壮多线程程序的基础。通过合理使用互斥锁、读写锁、条件变量、原子操作和线程局部存储,你可以有效避免多线程环境下的各种并发问题。

如果你喜欢这篇文章,请点赞/收藏/转发,后续我将持续更新更多关于 C/C++ 多线程编程的内容!


研究学习不易,点赞易。
工作生活不易,收藏易,点收藏不迷茫 :)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客不孤独

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值