首页 > 编程笔记

C语言多线程编程

C语言是一种支持多线程编程的语言,它通过线程来实现并发执行,可以大大提高程序的运行效率和响应速度。在本文中,我们将介绍 C语言中的多线程编程,包括线程的创建、同步、互斥、条件变量等方面。

线程的创建

在 C语言中,可以通过 pthread 库来创建线程。pthread 库是一个 POSIX 标准的线程库,可以在 Linux、Unix 等操作系统上使用。线程的创建需要用到 pthread_create 函数,它的原型如下:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
参数说明:

下面是一个简单的线程创建示例代码:
#include <stdio.h>
#include <pthread.h>

void *thread_func(void *arg) {
    printf("This is a new thread!\n");
    pthread_exit(NULL);
}

int main() {
    pthread_t tid;
    pthread_create(&tid, NULL, thread_func, NULL);
    printf("This is the main thread!\n");
    pthread_exit(NULL);
}
运行结果:

This is the main thread!
This is a new thread!

可以看到,在 main 函数中调用 pthread_create 函数创建了一个新线程,然后在新线程中执行了 thread_func 函数,并打印出"This is a new thread!"。同时,主线程也继续执行,并打印出"This is the main thread!"。

需要注意的是,在使用 pthread 库时,main 函数必须调用 pthread_exit 函数来结束程序,否则可能会出现线程无法正常退出的情况。

线程的同步

在多线程编程中,由于多个线程同时执行,可能会出现资源竞争的情况。为了避免这种情况,需要对线程进行同步。在 C语言中,可以使用互斥锁、条件变量等机制来实现线程同步。

1) 互斥锁

互斥锁是一种用于保护共享资源的锁,只有获得锁的线程才能访问共享资源。

在 C语言中,可以使用 pthread 库中的 pthread_mutex_init、pthread_mutex_lock、pthread_mutex_unlock、pthread_mutex_destroy 函数来实现互斥锁。其中,pthread_mutex_init 函数用于初始化互斥锁,pthread_mutex_lock 函数用于加锁,pthread_mutex_unlock 函数用于解锁,pthread_mutex_destroy 函数用于销毁互斥锁。

下面是一个使用互斥锁的示例代码:
#include <stdio.h>
#include <pthread.h>

int counter = 0;
pthread_mutex_t mutex;

void *thread_func(void *arg) {
    int i;
    for (i = 0; i < 1000000; i++) {
        pthread_mutex_lock(&mutex);
        counter++;
        pthread_mutex_unlock(&mutex);
    }
    pthread_exit(NULL);
}

int main() {
    pthread_t tid1, tid2;
    pthread_mutex_init(&mutex, NULL);
    pthread_create(&tid1, NULL, thread_func, NULL);
    pthread_create(&tid2, NULL, thread_func, NULL);
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_mutex_destroy(&mutex);
    printf("counter = %d\n", counter);
    pthread_exit(NULL);
}
运行结果:

counter = 2000000

可以看到,在 main 函数中创建了两个线程 tid1 和 tid2,它们的任务是分别对 counter 变量进行 1000000 次累加操作。由于 counter 变量是一个共享资源,因此需要使用互斥锁来保护它。

在线程函数中,首先调用 pthread_mutex_lock 函数获得锁,然后对 counter 变量进行操作,最后调用 pthread_mutex_unlock 函数释放锁。在 main 函数中,使用 pthread_join 函数等待线程 tid1 和 tid2 执行完毕,然后销毁互斥锁并打印出 counter 的最终值。

2) 条件变量

条件变量是一种用于线程间通信的机制,可以用于实现线程的等待和唤醒操作。

在 C语言中,可以使用 pthread 库中的 pthread_cond_init、pthread_cond_wait、pthread_cond_signal、pthread_cond_broadcast、pthread_cond_destroy 函数来实现条件变量。

其中,pthread_cond_init 函数用于初始化条件变量,pthread_cond_wait 函数用于等待条件变量,pthread_cond_signal 函数用于唤醒等待条件变量的线程,pthread_cond_broadcast 函数用于唤醒所有等待条件变量的线程,pthread_cond_destroy 函数用于销毁条件变量。

下面是一个使用条件变量的示例代码:
#include <stdio.h>
#include <pthread.h>

int buffer = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;

void *producer(void *arg) {
    int i;
    for (i = 0; i < 10; i++) {
        pthread_mutex_lock(&mutex);
        buffer++;
        printf("Producer produced %d\n", buffer);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
    pthread_exit(NULL);
}

void *consumer(void *arg) {
    int i;
    for (i = 0; i < 10; i++) {
        pthread_mutex_lock(&mutex);
        while (buffer == 0) {
            pthread_cond_wait(&cond, &mutex);
        }
        buffer--;
        printf("Consumer consumed %d\n", buffer);
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
    pthread_exit(NULL);
}

int main() {
    pthread_t tid1, tid2;
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);
    pthread_create(&tid1, NULL, producer, NULL);
    pthread_create(&tid2, consumer, NULL);
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    pthread_exit(NULL);
}
运行结果:

Producer produced 1
Consumer consumed 0
Producer produced 1
Consumer consumed 0
Producer produced 1
Consumer consumed 0
Producer produced 1
Consumer consumed 0
Producer produced 1
Consumer consumed 0
Producer produced 1
Consumer consumed 0
Producer produced 1
Consumer consumed 0
Producer produced 1
Consumer consumed 0
Producer produced 1
Consumer consumed 0
Producer produced 1
Consumer consumed 0

可以看到,该程序中有一个生产者线程和一个消费者线程,它们共享一个缓冲区变量 buffer。生产者线程负责将 buffer 逐个增加,消费者线程负责将 buffer 逐个减少。当 buffer 为 0 时,消费者线程将进入等待状态,等待生产者线程将 buffer 增加后发出信号唤醒自己。当 buffer 不为 0 时,生产者线程将向消费者线程发送一个信号,通知其可以开始消费。通过使用条件变量和互斥锁,生产者和消费者线程可以保证对 buffer 变量的操作是互斥的。

总结

本文介绍了 C语言中的多线程编程技术,包括线程的创建、同步和互斥、条件变量等。多线程编程是一种高级编程技术,需要程序员具备一定的计算机系统知识和编程经验。多线程编程可以提高程序的性能和并发能力,但也存在一些问题,例如线程安全、死锁等。在实际开发过程中,需要综合考虑多种因素,合理使用多线程技术,提高程序的质量和效率。

推荐阅读