当前位置:首页 > C > 正文

C语言线程同步机制详解(小白也能掌握的多线程同步技术)

在现代软件开发中,C语言线程同步是构建高性能、高并发应用程序的关键技术。当你使用C语言多线程编程时,多个线程可能同时访问共享资源,如全局变量、文件或内存区域。若不加以控制,就会导致数据竞争(Race Condition)、程序崩溃或结果不可预测。本文将带你从零开始,深入浅出地理解 C 语言中的线程同步机制。

为什么需要线程同步?

假设有两个线程同时对一个全局计数器加1:

#include <stdio.h>#include <pthread.h>int counter = 0;void* increment(void* arg) {    for (int i = 0; i < 100000; i++) {        counter++;  // 非原子操作!    }    return NULL;}int main() {    pthread_t t1, t2;    pthread_create(&t1, NULL, increment, NULL);    pthread_create(&t2, NULL, increment, NULL);    pthread_join(t1, NULL);    pthread_join(t2, NULL);    printf("Final counter value: %d\n", counter);  // 可能不是 200000!    return 0;}

这段代码看似会输出 200000,但由于 counter++ 不是原子操作(它包含读取、加1、写回三步),两个线程可能同时读取相同的值,导致最终结果小于预期。这就是典型的数据竞争问题。

C语言线程同步机制详解(小白也能掌握的多线程同步技术) C语言线程同步 C语言多线程编程 互斥锁 条件变量 第1张

解决方案一:互斥锁(Mutex)

互斥锁是最常用的线程同步机制之一。它确保同一时间只有一个线程可以访问临界区(Critical Section)。

#include <stdio.h>#include <pthread.h>int counter = 0;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  // 初始化互斥锁void* increment(void* arg) {    for (int i = 0; i < 100000; i++) {        pthread_mutex_lock(&mutex);   // 加锁        counter++;        pthread_mutex_unlock(&mutex); // 解锁    }    return NULL;}int main() {    pthread_t t1, t2;    pthread_create(&t1, NULL, increment, NULL);    pthread_create(&t2, NULL, increment, NULL);    pthread_join(t1, NULL);    pthread_join(t2, NULL);    printf("Final counter value: %d\n", counter);  // 现在一定是 200000    pthread_mutex_destroy(&mutex);  // 销毁互斥锁    return 0;}

通过使用 pthread_mutex_lock()pthread_mutex_unlock(),我们确保了 counter++ 操作的原子性。这就是 C语言线程同步中最基础也最重要的工具。

解决方案二:条件变量(Condition Variable)

当线程需要等待某个条件成立时(例如缓冲区非空),条件变量配合互斥锁可以高效实现线程间的协调。

#include <stdio.h>#include <pthread.h>#include <unistd.h>int buffer = 0;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cond = PTHREAD_COND_INITIALIZER;void* producer(void* arg) {    sleep(1);  // 模拟生产耗时    pthread_mutex_lock(&mutex);    buffer = 42;    printf("Produced: %d\n", buffer);    pthread_cond_signal(&cond);     // 唤醒等待的消费者    pthread_mutex_unlock(&mutex);    return NULL;}void* consumer(void* arg) {    pthread_mutex_lock(&mutex);    while (buffer == 0) {        pthread_cond_wait(&cond, &mutex);  // 等待条件成立    }    printf("Consumed: %d\n", buffer);    pthread_mutex_unlock(&mutex);    return NULL;}int main() {    pthread_t p, c;    pthread_create(&c, NULL, consumer, NULL);    pthread_create(&p, NULL, producer, NULL);    pthread_join(c, NULL);    pthread_join(p, NULL);    return 0;}

注意:pthread_cond_wait() 会自动释放互斥锁并阻塞线程,直到被 pthread_cond_signal() 唤醒,然后重新获取锁。这种机制避免了忙等待(Busy Waiting),提高了效率。

总结与最佳实践

  • 始终用互斥锁保护共享数据,避免数据竞争。
  • 使用条件变量实现线程间通信,不要用轮询(polling)。
  • 锁的范围要尽可能小,只包裹必要的临界区,以减少性能开销。
  • 注意死锁(Deadlock):避免嵌套锁,或按固定顺序加锁。

掌握 C语言多线程编程中的同步机制,不仅能写出正确的并发程序,还能显著提升程序性能。无论是开发服务器、嵌入式系统还是高性能计算应用,互斥锁条件变量都是你不可或缺的工具。

提示:编译多线程程序时记得加上 -lpthread 链接选项,例如:gcc program.c -o program -lpthread