Linux pthread线程怎么创建与使用

发布时间:2022-02-07 09:30:03 作者:iii
来源:亿速云 阅读:255
# Linux pthread线程怎么创建与使用

## 一、线程基础概念

### 1.1 什么是线程

线程(Thread)是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含多个线程,这些线程共享进程的资源(如内存空间、文件描述符等),但每个线程拥有自己独立的栈空间和程序计数器。

与进程相比,线程具有以下特点:
- 创建和切换开销更小
- 共享相同的地址空间
- 通信更加高效
- 更适合并行计算任务

### 1.2 POSIX线程(pthread)

POSIX线程(通常称为pthread)是IEEE POSIX 1003.1c标准定义的线程API,它是Unix-like系统中实现多线程编程的标准接口。Linux系统通过NPTL(Native POSIX Thread Library)实现了这一标准。

pthread库提供了以下核心功能:
- 线程创建与管理
- 线程同步(互斥锁、条件变量等)
- 线程特定数据
- 线程取消与控制

## 二、pthread线程创建

### 2.1 基本创建方法

在Linux中使用pthread_create函数创建线程:

```c
#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: 线程执行的函数 - arg: 传递给线程函数的参数

2.2 创建示例

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

void *thread_function(void *arg) {
    int *value = (int *)arg;
    printf("Thread received value: %d\n", *value);
    return NULL;
}

int main() {
    pthread_t thread_id;
    int value = 42;
    
    if (pthread_create(&thread_id, NULL, thread_function, &value) != 0) {
        perror("pthread_create failed");
        exit(EXIT_FLURE);
    }
    
    printf("Main thread created new thread\n");
    
    // 等待线程结束
    pthread_join(thread_id, NULL);
    
    return 0;
}

2.3 线程属性设置

pthread_attr_t结构体允许我们设置线程的各种属性:

pthread_attr_t attr;
pthread_attr_init(&attr);  // 初始化属性

// 设置线程为分离状态
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

// 设置栈大小
size_t stack_size = 1024 * 1024;  // 1MB
pthread_attr_setstacksize(&attr, stack_size);

// 创建带有自定义属性的线程
pthread_t thread;
pthread_create(&thread, &attr, thread_function, NULL);

// 销毁属性对象
pthread_attr_destroy(&attr);

三、线程同步机制

3.1 互斥锁(Mutex)

互斥锁用于保护共享资源,防止多个线程同时访问:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *thread_func(void *arg) {
    pthread_mutex_lock(&mutex);
    // 临界区代码
    pthread_mutex_unlock(&mutex);
    return NULL;
}

3.2 条件变量(Condition Variable)

条件变量用于线程间的通信:

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

// 等待线程
void *consumer(void *arg) {
    pthread_mutex_lock(&mutex);
    while (!ready) {
        pthread_cond_wait(&cond, &mutex);
    }
    // 处理数据
    pthread_mutex_unlock(&mutex);
    return NULL;
}

// 通知线程
void *producer(void *arg) {
    pthread_mutex_lock(&mutex);
    ready = 1;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
    return NULL;
}

3.3 读写锁(Read-Write Lock)

读写锁允许多个读操作同时进行,但写操作独占:

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

// 读锁
pthread_rwlock_rdlock(&rwlock);
// 读取共享数据
pthread_rwlock_unlock(&rwlock);

// 写锁
pthread_rwlock_wrlock(&rwlock);
// 修改共享数据
pthread_rwlock_unlock(&rwlock);

四、线程管理与控制

4.1 线程终止

线程可以通过以下方式终止: 1. 从线程函数返回 2. 调用pthread_exit() 3. 被其他线程取消

void *thread_func(void *arg) {
    // 方式1:返回
    return NULL;
    
    // 方式2:显式退出
    pthread_exit(NULL);
}

4.2 线程连接(join)

pthread_join用于等待线程结束并获取其返回值:

pthread_t thread;
void *thread_result;

pthread_create(&thread, NULL, thread_function, NULL);
pthread_join(thread, &thread_result);

4.3 线程分离(detach)

分离线程不需要被join,资源会自动回收:

pthread_t thread;
pthread_create(&thread, NULL, thread_function, NULL);
pthread_detach(thread);

4.4 线程取消(cancel)

pthread_t thread;
pthread_create(&thread, NULL, thread_function, NULL);

// 发送取消请求
pthread_cancel(thread);

// 线程函数中可以设置取消点
void *thread_func(void *arg) {
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    
    // 显式取消点
    pthread_testcancel();
    
    // 或者系统调用会自动成为取消点
    sleep(1);
    
    return NULL;
}

五、线程安全与最佳实践

5.1 线程安全函数

确保使用线程安全版本的函数: - rand() → rand_r() - strtok() → strtok_r() - localtime() → localtime_r()

5.2 避免死锁

死锁预防策略: 1. 按固定顺序获取锁 2. 使用trylock而非lock 3. 设置锁超时

// 尝试获取锁,避免死锁
if (pthread_mutex_trylock(&mutex) == 0) {
    // 获取锁成功
    pthread_mutex_unlock(&mutex);
} else {
    // 处理获取锁失败的情况
}

5.3 线程局部存储

使用__thread关键字或pthread_key_create创建线程特定数据:

// GCC扩展方式
static __thread int tls_var;

// POSIX标准方式
pthread_key_t key;

void destructor(void *value) {
    free(value);
}

void init_key() {
    pthread_key_create(&key, destructor);
}

void *thread_func(void *arg) {
    int *data = malloc(sizeof(int));
    *data = 42;
    pthread_setspecific(key, data);
    
    // 获取数据
    int *value = pthread_getspecific(key);
    printf("Thread local value: %d\n", *value);
    
    return NULL;
}

六、高级主题

6.1 线程池实现

线程池的基本结构:

typedef struct {
    pthread_t *threads;
    int thread_count;
    task_queue_t *queue;
    pthread_mutex_t lock;
    pthread_cond_t notify;
    int shutdown;
} thread_pool_t;

// 初始化线程池
thread_pool_t *thread_pool_create(int thread_count) {
    thread_pool_t *pool = malloc(sizeof(thread_pool_t));
    // 初始化各种成员和同步原语
    // 创建worker线程
    return pool;
}

// worker线程函数
void *worker_thread(void *arg) {
    thread_pool_t *pool = (thread_pool_t *)arg;
    while (1) {
        pthread_mutex_lock(&pool->lock);
        while (pool->queue->size == 0 && !pool->shutdown) {
            pthread_cond_wait(&pool->notify, &pool->lock);
        }
        // 获取任务并执行
        pthread_mutex_unlock(&pool->lock);
    }
    return NULL;
}

6.2 CPU亲和性设置

将线程绑定到特定CPU核心:

#include <sched.h>

void set_thread_affinity(pthread_t thread, int cpu_id) {
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(cpu_id, &cpuset);
    
    pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
}

6.3 实时线程调度

设置线程调度策略和优先级:

struct sched_param param;
param.sched_priority = sched_get_priority_max(SCHED_FIFO);

pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
pthread_attr_setschedparam(&attr, &param);
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

pthread_t thread;
pthread_create(&thread, &attr, realtime_thread_func, NULL);

七、性能调优与调试

7.1 线程数量选择

最佳线程数量通常与CPU核心数相关:

#include <unistd.h>

int get_optimal_thread_count() {
    long cores = sysconf(_SC_NPROCESSORS_ONLN);
    return cores > 0 ? (int)cores : 1;
}

7.2 线程竞争分析

使用工具检测线程竞争: - Valgrind Helgrind - gdb thread apply all bt - perf工具

7.3 常见问题排查

  1. 死锁:使用gdb检查线程堆栈
  2. 数据竞争:使用-fsanitize=thread编译选项
  3. 性能瓶颈:使用perf stat分析

八、实际应用案例

8.1 并行计算示例

计算π值的蒙特卡洛方法:

typedef struct {
    long long hits;
    long long samples;
} thread_data_t;

void *monte_carlo(void *arg) {
    thread_data_t *data = (thread_data_t *)arg;
    unsigned int seed = time(NULL) ^ pthread_self();
    
    for (long long i = 0; i < data->samples; i++) {
        double x = (double)rand_r(&seed) / RAND_MAX;
        double y = (double)rand_r(&seed) / RAND_MAX;
        if (x*x + y*y <= 1.0) {
            data->hits++;
        }
    }
    return NULL;
}

double calculate_pi(int thread_count, long long total_samples) {
    pthread_t threads[thread_count];
    thread_data_t thread_data[thread_count];
    
    long long samples_per_thread = total_samples / thread_count;
    
    for (int i = 0; i < thread_count; i++) {
        thread_data[i].hits = 0;
        thread_data[i].samples = samples_per_thread;
        pthread_create(&threads[i], NULL, monte_carlo, &thread_data[i]);
    }
    
    long long total_hits = 0;
    for (int i = 0; i < thread_count; i++) {
        pthread_join(threads[i], NULL);
        total_hits += thread_data[i].hits;
    }
    
    return 4.0 * total_hits / total_samples;
}

8.2 生产者-消费者模型

#define BUFFER_SIZE 10

typedef struct {
    int buffer[BUFFER_SIZE];
    int count;
    int in;
    int out;
    pthread_mutex_t mutex;
    pthread_cond_t not_empty;
    pthread_cond_t not_full;
} buffer_t;

void *producer(void *arg) {
    buffer_t *buf = (buffer_t *)arg;
    for (int i = 0; i < 100; i++) {
        pthread_mutex_lock(&buf->mutex);
        while (buf->count == BUFFER_SIZE) {
            pthread_cond_wait(&buf->not_full, &buf->mutex);
        }
        
        buf->buffer[buf->in] = i;
        buf->in = (buf->in + 1) % BUFFER_SIZE;
        buf->count++;
        
        pthread_cond_signal(&buf->not_empty);
        pthread_mutex_unlock(&buf->mutex);
    }
    return NULL;
}

void *consumer(void *arg) {
    buffer_t *buf = (buffer_t *)arg;
    for (int i = 0; i < 100; i++) {
        pthread_mutex_lock(&buf->mutex);
        while (buf->count == 0) {
            pthread_cond_wait(&buf->not_empty, &buf->mutex);
        }
        
        int item = buf->buffer[buf->out];
        buf->out = (buf->out + 1) % BUFFER_SIZE;
        buf->count--;
        
        pthread_cond_signal(&buf->not_full);
        pthread_mutex_unlock(&buf->mutex);
        
        printf("Consumed: %d\n", item);
    }
    return NULL;
}

九、总结

本文全面介绍了Linux下pthread线程的创建与使用方法,包括:

  1. 线程基础概念和POSIX线程标准
  2. 线程创建的各种方法和属性设置
  3. 线程同步机制(互斥锁、条件变量、读写锁)
  4. 线程管理与控制(终止、连接、分离、取消)
  5. 线程安全与最佳实践
  6. 高级主题如线程池、CPU亲和性和实时调度
  7. 性能调优与调试技巧
  8. 实际应用案例

通过合理使用多线程技术,可以显著提高程序的并发性能和资源利用率。然而,多线程编程也带来了复杂性,需要开发者特别注意线程安全和同步问题。

掌握pthread编程是Linux系统开发的重要技能,希望本文能为读者提供全面的指导和参考。在实践中,建议从简单案例开始,逐步构建更复杂的多线程应用,同时充分利用调试工具来确保程序的正确性和稳定性。 “`

推荐阅读:
  1. linux中pthread_create的使用方法
  2. Linux多线程编程的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

linux pthread

上一篇:node_modules中怎么修改依赖库

下一篇:仅使用一个div配合css实现饼状图的方法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》