C语言基础系列【36】多线程编程

博主介绍:程序喵大人

多线程编程是一种在程序中同时执行多个线程(子任务)的技术。

线程是程序中的一个执行单元,每个线程都有自己的执行路径和上下文。

一个进程可以包含多个线程,这些线程可以并发执行,共享进程的内存空间和资源,但拥有各自的栈空间和寄存器状态。

为什么要多线程?

举个例子,100个人需要坐车从故宫到颐和园,一个车可以坐5个人,如果我们只有1个车,那需要20个往返,非常耗费时间。而如果我们有10个车,那就只需要2个往返的时间,肯定更快。

多线程的优势主要有:

  • 并发性:多线程使程序可以同时执行多个任务,提高程序的并发性,可以更充分地利用多核处理器。
  • 响应性:多线程可以使程序响应用户输入或外部事件,内部复杂的逻辑在其它线程执行,保持界面的活跃性。
  • 资源共享:多线程允许线程之间共享内存和资源,可以降低资源消耗,提高效率。
  • 模块化:多线程可以将复杂任务分解为多个独立的线程,每个线程运行一部分任务,使程序更易于维护和扩展,且提高程序的效率。

POSIX线程库(pthread)

POSIX线程库(pthread)是一个在UNIX和类UNIX系统(如Linux)上实现的标准多线程API。它提供了一组函数来创建、管理和控制线程,以及实现线程之间的同步。

常用的pthread函数包括:

  • 线程管理函数
    • pthread_create:创建一个新线程,并使其从指定的函数开始运行。
    • pthread_exit:终止当前线程,返回一个值给pthread_join()
    • pthread_join:阻塞调用线程,直到指定的线程终止,并获取其返回值。
    • pthread_self:返回调用线程的线程ID。
    • pthread_detach:将指定的线程设置为分离状态,当线程执行完毕后会自动释放资源。
  • 线程同步函数
    • pthread_mutex_init:初始化一个互斥锁(mutex),用于保护共享资源。
    • pthread_mutex_lock:锁定互斥锁。
    • pthread_mutex_unlock:解锁互斥锁。
    • pthread_mutex_destroy:销毁互斥锁,释放其使用的资源。
    • pthread_cond_wait:等待条件变量被满足。
    • pthread_cond_signal:唤醒一个等待该条件变量的线程。

线程的创建与同步

线程的创建

在C语言中,使用pthread_create函数来创建新线程。函数的基本用法如下:

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
  • thread:用于存储新线程的标识符。
  • attr:线程属性,通常可以设置为NULL。
  • start_routine:新线程的入口函数,该函数接受一个void*参数并返回void*
  • arg:传递给start_routine的参数。

以下示例,演示如何创建一个新线程:

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

void* print_hello(void* arg) {
    printf("Hello from new thread!\n");
    return NULL;
}

int main() {
    pthread_t tid; // 线程标识符
    pthread_create(&tid, NULL, print_hello, NULL);
    pthread_join(tid, NULL); // 等待新线程结束
    printf("Main thread: New thread has finished.\n");
    return 0;
}
线程的同步

当多个线程同时访问共享资源时,可能会出现竞争条件,导致数据错误。为了避免竞争条件,可以使用互斥锁(Mutex)进行线程同步。

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

pthread_mutex_t mutex;
int shared_counter = 0;

void* increment_counter(void* arg) {
    for (int i = 0; i < 1000; ++i) {
        pthread_mutex_lock(&mutex);
        shared_counter++;
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    pthread_mutex_init(&mutex, NULL);

    pthread_create(&thread1, NULL, increment_counter, NULL);
    pthread_create(&thread2, NULL, increment_counter, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("Final counter value: %d\n", shared_counter);
    pthread_mutex_destroy(&mutex);

    return 0;
}

在这个示例中,两个线程同时运行,每个线程都尝试增加共享计数器shared_counter的值。

通过使用互斥锁,我们确保了每次只有一个线程可以访问和修改shared_counter,从而避免了竞态条件。

线程安全与互斥锁

线程安全是指多线程程序在并发执行时能够正确访问和修改共享资源,而不会导致数据不一致或程序崩溃等奇奇怪怪的问题。

而为了保证线程安全,通常都需要使用同步机制,如互斥锁(Mutex)。

互斥锁是一种用于保护共享资源的同步机制。当一个线程持有互斥锁时,其他线程无法访问该资源,直到锁被释放为止。这确保了资源在任何时候都只能被一个线程访问,从而避免了竞竞条件。

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

pthread_mutex_t mutex;
int shared_data = 0;

void* thread_function(void* arg) {
    for (int i = 0; i < 1000; ++i) {
        pthread_mutex_lock(&mutex);
        // 访问和修改共享数据
        shared_data++;
        printf("Thread %ld: shared_data = %d\n", pthread_self(), shared_data);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_t threads[2];
    pthread_mutex_init(&mutex, NULL);

    pthread_create(&threads[0], NULL, thread_function, NULL);
    pthread_create(&threads[1], NULL, thread_function, NULL);

    pthread_join(threads[0], NULL);
    pthread_join(threads[1], NULL);

    printf("Final shared_data value: %d\n", shared_data);
    pthread_mutex_destroy(&mutex);

    return 0;
}

在这个示例中,两个线程同时运行,并尝试访问和修改共享数据shared_data。通过使用互斥锁,我们确保了每次只有一个线程可以访问和修改shared_data,从而保证了线程安全。

为了避免竞争条件,保证线程安全,除了使用互斥锁,我们还可以使用原子变量,也推荐你了解下原子操作。

码字不易,欢迎大家点赞关注评论,谢谢!


C++训练营

专为校招、社招3年工作经验的同学打造的1V1 C++训练营,量身定制学习计划、每日代码review,简历优化,面试辅导,已帮助多名学员获得大厂offer!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序喵大人

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

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

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

打赏作者

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

抵扣说明:

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

余额充值