074. 理解C语言中的多线程编程

C语言中的多线程编程允许程序同时执行多个任务,从而提高程序的效率和响应能力。多线程编程在现代软件开发中非常重要,尤其是在需要处理并发任务或提高性能的场景中。C语言标准库(C11)提供了线程支持,但更常见的多线程编程是通过POSIX线程(pthread)库实现的。

1. POSIX线程(pthread)

POSIX线程(pthread)是POSIX标准中定义的线程库,广泛用于类Unix系统(如Linux和macOS)。以下是一些基本的pthread函数及其用法。

1.1 创建线程

使用pthread_create函数创建线程。

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

void* threadFunction(void* arg) {
    printf("线程执行中...\n");
    return NULL;
}

int main() {
    pthread_t thread;
    if (pthread_create(&thread, NULL, threadFunction, NULL) != 0) {
        perror("线程创建失败");
        return 1;
    }

    // 等待线程结束
    if (pthread_join(thread, NULL) != 0) {
        perror("线程等待失败");
        return 1;
    }

    return 0;
}

1.2 线程同步

线程同步是多线程编程中的一个重要概念,用于防止数据竞争和保证线程安全。常见的同步机制包括互斥锁(mutex)、条件变量和读写锁。

1.2.1 互斥锁(Mutex)

互斥锁用于保护共享资源,确保同一时间只有一个线程可以访问该资源。

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

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int sharedVariable = 0;

void* incrementFunction(void* arg) {
    for (int i = 0; i < 100000; i++) {
        pthread_mutex_lock(&mutex);
        sharedVariable++;
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    if (pthread_create(&thread1, NULL, incrementFunction, NULL) != 0) {
        perror("线程创建失败");
        return 1;
    }
    if (pthread_create(&thread2, NULL, incrementFunction, NULL) != 0) {
        perror("线程创建失败");
        return 1;
    }

    if (pthread_join(thread1, NULL) != 0) {
        perror("线程等待失败");
        return 1;
    }
    if (pthread_join(thread2, NULL) != 0) {
        perror("线程等待失败");
        return 1;
    }

    printf("共享变量的值: %d\n", sharedVariable);

    return 0;
}

1.2.2 条件变量

条件变量用于线程间的同步,允许线程在某个条件满足时继续执行。

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

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int conditionMet = 0;

void* waitingFunction(void* arg) {
    pthread_mutex_lock(&mutex);
    while (!conditionMet) {
        pthread_cond_wait(&cond, &mutex);
    }
    printf("条件已满足,线程继续执行...\n");
    pthread_mutex_unlock(&mutex);
    return NULL;
}

void* signalingFunction(void* arg) {
    pthread_mutex_lock(&mutex);
    conditionMet = 1;
    pthread_cond_signal(&cond);
    printf("条件已设置,通知等待线程...\n");
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    if (pthread_create(&thread1, NULL, waitingFunction, NULL) != 0) {
        perror("线程创建失败");
        return 1;
    }
    if (pthread_create(&thread2, NULL, signalingFunction, NULL) != 0) {
        perror("线程创建失败");
        return 1;
    }

    if (pthread_join(thread1, NULL) != 0) {
        perror("线程等待失败");
        return 1;
    }
    if (pthread_join(thread2, NULL) != 0) {
        perror("线程等待失败");
        return 1;
    }

    return 0;
}

2. C11线程支持

C11标准引入了线程支持,提供了<threads.h>头文件,用于线程操作。

2.1 创建线程

#include <stdio.h>
#include <threads.h>

int threadFunction(void* arg) {
    printf("线程执行中...\n");
    return 0;
}

int main() {
    thrd_t thread;
    if (thrd_create(&thread, threadFunction, NULL) != thrd_success) {
        perror("线程创建失败");
        return 1;
    }

    // 等待线程结束
    if (thrd_join(thread, NULL) != thrd_success) {
        perror("线程等待失败");
        return 1;
    }

    return 0;
}

2.2 线程同步

C11标准也提供了互斥锁和条件变量的支持。

2.2.1 互斥锁

#include <stdio.h>
#include <threads.h>

mtx_t mutex;
int sharedVariable = 0;

int incrementFunction(void* arg) {
    for (int i = 0; i < 100000; i++) {
        mtx_lock(&mutex);
        sharedVariable++;
        mtx_unlock(&mutex);
    }
    return 0;
}

int main() {
    thrd_t thread1, thread2;

    mtx_init(&mutex, mtx_plain);

    if (thrd_create(&thread1, incrementFunction, NULL) != thrd_success) {
        perror("线程创建失败");
        return 1;
    }
    if (thrd_create(&thread2, incrementFunction, NULL) != thrd_success) {
        perror("线程创建失败");
        return 1;
    }

    if (thrd_join(thread1, NULL) != thrd_success) {
        perror("线程等待失败");
        return 1;
    }
    if (thrd_join(thread2, NULL) != thrd_success) {
        perror("线程等待失败");
        return 1;
    }

    printf("共享变量的值: %d\n", sharedVariable);

    mtx_destroy(&mutex);

    return 0;
}

3. 注意事项

  1. 线程安全:使用互斥锁或其他同步机制保护共享资源,避免数据竞争。

  2. 线程同步:使用条件变量或信号量来协调线程间的执行顺序。

  3. 线程销毁:确保线程结束后释放相关资源,避免内存泄漏。

  4. 线程数量:创建过多的线程可能会导致系统资源耗尽,合理控制线程数量。

  5. 线程库的选择:POSIX线程(pthread)是类Unix系统中广泛使用的线程库,功能丰富。C11线程支持是C语言标准的一部分,但支持的编译器可能较少。

4. 总结

多线程编程是C语言中一个强大的工具,可以显著提高程序的性能和响应能力。通过使用POSIX线程(pthread)或C11线程支持,可以实现线程的创建、同步和销毁。合理使用线程同步机制,如互斥锁和条件变量,可以避免数据竞争和线程安全问题。在实际开发中,应根据具体需求选择合适的线程库和同步机制。

视频讲解

BiliBili: 视睿网络-哔哩哔哩视频 (bilibili.com)