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

如何用C语言创建线程

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

如何用C语言创建线程

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

本文将详细介绍如何使用C语言创建线程,包括POSIX线程库的基本概念、线程创建的具体步骤、线程同步与互斥机制、线程池的实现以及线程安全的最佳实践。

要用C语言创建线程,可以使用POSIX线程库(pthread)。POSIX线程库提供了一组API函数来创建和管理线程,pthread_create和pthread_join是其中最常用的两个函数。在创建线程时,需要定义一个函数作为新线程的入口点。例如,pthread_create函数用于创建一个新线程,而pthread_join函数用于等待线程的执行完成。接下来,我将详细描述如何使用这些函数以及线程管理的相关内容。

一、POSIX线程库简介

POSIX线程库,也称为pthread库,是一种用于多线程编程的标准接口。它提供了一组函数,用于创建和管理线程。POSIX线程库的优点包括可移植性、灵活性和强大的功能支持。主要的POSIX线程库函数包括pthread_create、pthread_join、pthread_exit、pthread_cancel等。

1. pthread_create函数

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

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

参数说明:

  • thread:指向线程标识符的指针。
  • attr:线程属性,通常为NULL。
  • start_routine:新线程将执行的函数。
  • arg:传递给start_routine的参数。

2. pthread_join函数

pthread_join函数用于等待线程的执行完成。其函数原型如下:

int pthread_join(pthread_t thread, void retval);  

参数说明:

  • thread:线程标识符。
  • retval:指向线程返回值的指针。

二、线程创建的基本步骤

创建线程的基本步骤包括:定义线程函数、创建线程和等待线程完成。下面是一个简单的示例,展示了如何使用pthread_create和pthread_join函数。

1. 定义线程函数

首先,定义一个线程函数,作为新线程的入口点。该函数的签名必须匹配pthread_create函数的要求,即返回类型为void*,参数类型为void*。

#include <stdio.h>  
#include <pthread.h>  
void* thread_function(void* arg) {  
    int* num = (int*) arg;  
    printf("Thread is running. Argument: %dn", *num);  
    return NULL;  
}  

2. 创建线程

在main函数中,使用pthread_create函数创建一个新线程,并传递参数。

int main() {  
    pthread_t thread;  
    int arg = 42;  
    if (pthread_create(&thread, NULL, thread_function, &arg) != 0) {  
        fprintf(stderr, "Error creating threadn");  
        return 1;  
    }  
    // 等待线程完成  
    if (pthread_join(thread, NULL) != 0) {  
        fprintf(stderr, "Error joining threadn");  
        return 2;  
    }  
    printf("Main thread is done.n");  
    return 0;  
}  

三、线程同步与互斥

在多线程编程中,同步与互斥是两个重要的概念,用于确保线程之间的正确通信和资源共享。POSIX线程库提供了多种同步与互斥机制,如互斥锁(Mutex)、条件变量(Condition Variable)和读写锁(Read-Write Lock)。

1. 互斥锁(Mutex)

互斥锁用于保护共享资源,确保同一时间只有一个线程访问该资源。其主要API函数包括pthread_mutex_init、pthread_mutex_lock、pthread_mutex_unlock和pthread_mutex_destroy。

#include <stdio.h>  
#include <pthread.h>  
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  
int shared_data = 0;  
void* thread_function(void* arg) {  
    pthread_mutex_lock(&mutex);  
    shared_data++;  
    printf("Thread: shared_data = %dn", shared_data);  
    pthread_mutex_unlock(&mutex);  
    return NULL;  
}  
int main() {  
    pthread_t thread1, thread2;  
    pthread_create(&thread1, NULL, thread_function, NULL);  
    pthread_create(&thread2, NULL, thread_function, NULL);  
    pthread_join(thread1, NULL);  
    pthread_join(thread2, NULL);  
    pthread_mutex_destroy(&mutex);  
    printf("Main thread: shared_data = %dn", shared_data);  
    return 0;  
}  

2. 条件变量(Condition Variable)

条件变量用于线程间的等待和通知机制。其主要API函数包括pthread_cond_init、pthread_cond_wait、pthread_cond_signal和pthread_cond_destroy。

#include <stdio.h>  
#include <pthread.h>  
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;  
int ready = 0;  
void* thread_function(void* arg) {  
    pthread_mutex_lock(&mutex);  
    while (!ready) {  
        pthread_cond_wait(&cond, &mutex);  
    }  
    printf("Thread: Condition met, proceeding...n");  
    pthread_mutex_unlock(&mutex);  
    return NULL;  
}  
int main() {  
    pthread_t thread;  
    pthread_create(&thread, NULL, thread_function, NULL);  
    sleep(1); // 模拟一些工作  
    pthread_mutex_lock(&mutex);  
    ready = 1;  
    pthread_cond_signal(&cond);  
    pthread_mutex_unlock(&mutex);  
    pthread_join(thread, NULL);  
    pthread_mutex_destroy(&mutex);  
    pthread_cond_destroy(&cond);  
    printf("Main thread: Condition met, proceeding...n");  
    return 0;  
}  

四、线程池

线程池是一种常见的线程管理模式,预先创建一组线程,这些线程在需要时被重复利用,从而避免频繁创建和销毁线程的开销。

1. 线程池的实现

实现一个简单的线程池,需要包含以下几个部分:线程池初始化、任务队列、线程函数和销毁线程池。

#include <stdio.h>  
#include <stdlib.h>  
#include <pthread.h>  
#include <unistd.h>  
#define THREAD_POOL_SIZE 4  
#define TASK_QUEUE_SIZE 10  
typedef struct {  
    void (*function)(void*);  
    void* argument;  
} task_t;  
typedef struct {  
    pthread_mutex_t mutex;  
    pthread_cond_t cond;  
    pthread_t threads[THREAD_POOL_SIZE];  
    task_t task_queue[TASK_QUEUE_SIZE];  
    int task_count;  
    int head;  
    int tail;  
    int stop;  
} thread_pool_t;  
thread_pool_t pool;  
void* thread_function(void* 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_t task = pool.task_queue[pool.head];  
        pool.head = (pool.head + 1) % TASK_QUEUE_SIZE;  
        pool.task_count--;  
        pthread_mutex_unlock(&pool.mutex);  
        task.function(task.argument);  
    }  
    return NULL;  
}  
void thread_pool_init() {  
    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, thread_function, NULL);  
    }  
}  
void thread_pool_add_task(void (*function)(void*), void* arg) {  
    pthread_mutex_lock(&pool.mutex);  
    task_t task;  
    task.function = function;  
    task.argument = arg;  
    pool.task_queue[pool.tail] = task;  
    pool.tail = (pool.tail + 1) % TASK_QUEUE_SIZE;  
    pool.task_count++;  
    pthread_cond_signal(&pool.cond);  
    pthread_mutex_unlock(&pool.mutex);  
}  
void thread_pool_destroy() {  
    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 sample_task(void* arg) {  
    int num = *(int*)arg;  
    printf("Executing task: %dn", num);  
    sleep(1);  
}  
int main() {  
    thread_pool_init();  
    int tasks[10];  
    for (int i = 0; i < 10; i++) {  
        tasks[i] = i + 1;  
        thread_pool_add_task(sample_task, &tasks[i]);  
    }  
    sleep(5); // 等待所有任务完成  
    thread_pool_destroy();  
    printf("Main thread: All tasks completed.n");  
    return 0;  
}  

五、线程安全与最佳实践

在多线程编程中,确保线程安全是至关重要的。以下是一些最佳实践:

1. 使用互斥锁保护共享资源

当多个线程访问共享资源时,使用互斥锁保护这些资源,以避免数据竞争和不一致性。

2. 避免死锁

在使用多个锁时,确保遵循一致的锁定顺序,避免死锁的发生。尽量减少锁的持有时间,避免长时间占用锁。

3. 使用线程池优化性能

使用线程池可以减少线程创建和销毁的开销,提高系统性能。合理配置线程池的大小,避免过多或过少的线程。

4. 关注内存管理

在多线程环境中,合理管理内存,避免内存泄漏和非法访问。使用动态内存分配时,确保正确释放内存。

六、总结

用C语言创建线程主要依赖于POSIX线程库,通过pthread_create和pthread_join函数实现线程的创建和管理。线程同步与互斥是多线程编程中的重要概念,互斥锁和条件变量是常用的同步机制。线程池是一种高效的线程管理模式,能够提高系统性能。在多线程编程中,确保线程安全,避免死锁和内存管理问题,是编写高质量代码的关键。通过遵循这些最佳实践,可以有效提升多线程程序的稳定性和性能。

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