问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

C语言多线程编程入门:从基础到高级实战

创作时间:
作者:
@小白创作中心

C语言多线程编程入门:从基础到高级实战

引用
1
来源
1.
https://docs.pingcode.com/baike/1159722

本文将详细介绍如何在C语言中使用POSIX线程库(pthread)创建和管理线程。从基础的线程创建到高级的线程池实现,通过代码示例和详细解释,帮助读者全面理解C语言多线程编程。

一、包含pthread.h头文件

要在C语言中使用POSIX线程库,首先需要包含pthread.h头文件。该头文件提供了创建和管理线程所需的所有函数和数据类型。

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

二、调用pthread_create函数

pthread_create函数用于创建新线程。其函数原型如下:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

其中,参数解释如下:

  • pthread_t *thread:指向线程标识符的指针。
  • const pthread_attr_t *attr:指向线程属性对象的指针,通常设为NULL使用默认属性。
  • void *(*start_routine)(void *):指向线程函数的指针,该函数将在新线程中执行。
  • void *arg:传递给线程函数的参数。

三、传递线程函数和参数

线程函数是新线程将要执行的代码。该函数必须符合特定的函数签名,即返回类型为void *,参数为void *。可以通过arg参数将任意类型的数据传递给线程函数。

四、示例代码

下面是一个简单的示例代码,演示如何在C语言中创建线程并传递参数。

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

// 线程函数
void *thread_function(void *arg) {
    int *num = (int *)arg;
    printf("线程中的数字: %d\n", *num);
    return NULL;
}

int main() {
    pthread_t thread;
    int num = 42;

    // 创建线程
    if (pthread_create(&thread, NULL, thread_function, &num) != 0) {
        fprintf(stderr, "线程创建失败\n");
        return 1;
    }

    // 等待线程结束
    if (pthread_join(thread, NULL) != 0) {
        fprintf(stderr, "线程等待失败\n");
        return 2;
    }

    printf("主线程结束\n");
    return 0;
}

五、线程同步

在多线程编程中,线程同步是一个重要的概念。它确保多个线程在访问共享资源时不会产生竞争条件。POSIX线程库提供了一些同步机制,如互斥锁(mutex)和条件变量。

六、互斥锁

互斥锁用于保护共享资源,确保在同一时间只有一个线程访问该资源。使用互斥锁时,线程在访问共享资源前必须先锁定互斥锁,访问完成后解锁互斥锁。

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

pthread_mutex_t mutex;
int shared_data = 0;

void *thread_function(void *arg) {
    pthread_mutex_lock(&mutex);
    shared_data++;
    printf("线程更新后的共享数据: %d\n", shared_data);
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    // 初始化互斥锁
    if (pthread_mutex_init(&mutex, NULL) != 0) {
        fprintf(stderr, "互斥锁初始化失败\n");
        return 1;
    }

    // 创建线程
    if (pthread_create(&thread1, NULL, thread_function, NULL) != 0) {
        fprintf(stderr, "线程1创建失败\n");
        return 2;
    }
    if (pthread_create(&thread2, NULL, thread_function, NULL) != 0) {
        fprintf(stderr, "线程2创建失败\n");
        return 3;
    }

    // 等待线程结束
    if (pthread_join(thread1, NULL) != 0) {
        fprintf(stderr, "线程1等待失败\n");
        return 4;
    }
    if (pthread_join(thread2, NULL) != 0) {
        fprintf(stderr, "线程2等待失败\n");
        return 5;
    }

    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);
    printf("主线程结束\n");
    return 0;
}

七、条件变量

条件变量用于线程间的通信,允许一个线程等待另一个线程发出信号。条件变量通常与互斥锁一起使用,以确保对共享资源的访问是受保护的。

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

pthread_mutex_t mutex;
pthread_cond_t cond;
int ready = 0;

void *thread_function(void *arg) {
    pthread_mutex_lock(&mutex);
    while (!ready) {
        pthread_cond_wait(&cond, &mutex);
    }
    printf("线程收到信号\n");
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main() {
    pthread_t thread;

    // 初始化互斥锁和条件变量
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);

    // 创建线程
    if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
        fprintf(stderr, "线程创建失败\n");
        return 1;
    }

    // 主线程发送信号
    pthread_mutex_lock(&mutex);
    ready = 1;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);

    // 等待线程结束
    if (pthread_join(thread, NULL) != 0) {
        fprintf(stderr, "线程等待失败\n");
        return 2;
    }

    // 销毁互斥锁和条件变量
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    printf("主线程结束\n");
    return 0;
}

八、线程池

线程池是一组预先创建的线程,可以提高程序性能,特别是在需要频繁创建和销毁线程的情况下。通过重用现有线程,线程池减少了创建和销毁线程的开销。

九、创建线程池

要实现线程池,需要定义一个线程池结构体,包含线程数组、任务队列和同步机制。然后,创建线程并将它们放入池中,线程将从任务队列中提取任务并执行。

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

#define THREAD_POOL_SIZE 4
#define QUEUE_SIZE 10

typedef struct {
    void (*function)(void *);
    void *argument;
} Task;

typedef struct {
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    pthread_t threads[THREAD_POOL_SIZE];
    Task task_queue[QUEUE_SIZE];
    int task_count;
    int head;
    int tail;
    int stop;
} ThreadPool;

void *worker_thread(void *arg) {
    ThreadPool *pool = (ThreadPool *)arg;
    while (1) {
        pthread_mutex_lock(&pool->mutex);
        while (pool->task_count == 0 && !pool->stop) {
            pthread_cond_wait(&pool->cond, &pool->mutex);
        }
        if (pool->stop) {
            pthread_mutex_unlock(&pool->mutex);
            break;
        }
        Task task = pool->task_queue[pool->head];
        pool->head = (pool->head + 1) % QUEUE_SIZE;
        pool->task_count--;
        pthread_mutex_unlock(&pool->mutex);
        task.function(task.argument);
    }
    return NULL;
}

void thread_pool_init(ThreadPool *pool) {
    pthread_mutex_init(&pool->mutex, NULL);
    pthread_cond_init(&pool->cond, NULL);
    pool->task_count = 0;
    pool->head = 0;
    pool->tail = 0;
    pool->stop = 0;
    for (int i = 0; i < THREAD_POOL_SIZE; i++) {
        pthread_create(&pool->threads[i], NULL, worker_thread, pool);
    }
}

void thread_pool_destroy(ThreadPool *pool) {
    pthread_mutex_lock(&pool->mutex);
    pool->stop = 1;
    pthread_cond_broadcast(&pool->cond);
    pthread_mutex_unlock(&pool->mutex);
    for (int i = 0; i < THREAD_POOL_SIZE; i++) {
        pthread_join(pool->threads[i], NULL);
    }
    pthread_mutex_destroy(&pool->mutex);
    pthread_cond_destroy(&pool->cond);
}

void thread_pool_add_task(ThreadPool *pool, void (*function)(void *), void *argument) {
    pthread_mutex_lock(&pool->mutex);
    pool->task_queue[pool->tail].function = function;
    pool->task_queue[pool->tail].argument = argument;
    pool->tail = (pool->tail + 1) % QUEUE_SIZE;
    pool->task_count++;
    pthread_cond_signal(&pool->cond);
    pthread_mutex_unlock(&pool->mutex);
}

void sample_task(void *arg) {
    int *num = (int *)arg;
    printf("线程池任务: %d\n", *num);
    sleep(1); // 模拟任务处理时间
}

int main() {
    ThreadPool pool;
    thread_pool_init(&pool);
    for (int i = 0; i < 20; i++) {
        int *num = malloc(sizeof(int));
        *num = i;
        thread_pool_add_task(&pool, sample_task, num);
    }
    sleep(10); // 等待所有任务完成
    thread_pool_destroy(&pool);
    printf("主线程结束\n");
    return 0;
}

十、总结

在C语言中使用POSIX线程库(pthread)可以方便地创建和管理线程,从而实现并发编程。通过使用互斥锁、条件变量等同步机制,可以有效地避免竞争条件,确保线程安全。同时,通过实现线程池,可以提高程序性能,特别是在需要频繁创建和销毁线程的情况下。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号