超全面的线程编程实战指南

在这里插入图片描述

第一部分:线程基本概念

一、线程简介

线程是操作系统能够进行运算调度的最小单位,它是一个进程内的独立控制流。线程之间共享同一进程的资源,如内存空间和其他系统资源。

二、线程的优势
  1. 效率高:由于线程共享相同的地址空间,因此线程之间的通信非常快速。
  2. 灵活性:线程可以并行执行任务,提高了应用程序的响应速度和性能。
  3. 资源节约:线程共享进程的资源,减少了资源开销。

第二部分:线程创建与管理

三、创建线程

在POSIX系统中,使用 pthread_create() 函数创建一个新的线程。此函数需要四个参数:线程标识符的引用、线程属性对象、线程入口点函数的指针、以及传递给线程函数的参数。

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

void* threadFunction(void* arg) {
    // 线程执行体
    printf("Thread running\n");
    return NULL;
}

int main() {
    pthread_t thread;
    if (pthread_create(&thread, NULL, threadFunction, NULL) == 0) {
        printf("Thread created\n");
        pthread_join(thread, NULL); // 等待线程结束
    }
    return 0;
}
四、线程属性

线程可以有不同的属性,如是否可以被取消、调度策略等。这些属性可以通过 pthread_attr_t 结构体设置。

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

void* threadFunction(void* arg) {
    printf("Thread running\n");
    return NULL;
}

int main() {
    pthread_t thread;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // 设置分离属性
    if (pthread_create(&thread, &attr, threadFunction, NULL) == 0) {
        printf("Thread created\n");
    }
    pthread_attr_destroy(&attr); // 销毁属性对象
    return 0;
}

在这里插入图片描述

第三部分:线程同步

五、互斥锁 Mutex

互斥锁(Mutex)是用于保护临界区的最常见同步机制之一,它可以确保一次只有一个线程能够进入临界区。

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

int counter = 0;
pthread_mutex_t mutex;

void* incrementCounter(void* arg) {
    for (int i = 0; i < 1000000; ++i) {
        pthread_mutex_lock(&mutex);
        counter++;
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_mutex_init(&mutex, NULL);

    pthread_t threads[2];
    for (int i = 0; i < 2; ++i) {
        pthread_create(&threads[i], NULL, incrementCounter, NULL);
    }

    for (int i = 0; i < 2; ++i) {
        pthread_join(threads[i], NULL);
    }

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

    return 0;
}
六、条件变量 Condition Variables

条件变量常用于线程间的协作,如生产者消费者模式中用于同步生产者和消费者的执行。

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

#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];
int head = 0;
int tail = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t full = PTHREAD_COND_INITIALIZER;
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;

void* producer(void* arg) {
    int value = 0;
    while (1) {
        pthread_mutex_lock(&mutex);
        while ((head + 1) % BUFFER_SIZE == tail) {
            pthread_cond_wait(&full, &mutex);
        }
        buffer[head] = value++;
        head = (head + 1) % BUFFER_SIZE;
        pthread_cond_signal(&empty);
        pthread_mutex_unlock(&mutex);
        usleep(1000);
    }
    return NULL;
}

void* consumer(void* arg) {
    while (1) {
        pthread_mutex_lock(&mutex);
        while (head == tail) {
            pthread_cond_wait(&empty, &mutex);
        }
        int value = buffer[tail];
        tail = (tail + 1) % BUFFER_SIZE;
        pthread_cond_signal(&full);
        pthread_mutex_unlock(&mutex);
        printf("Consumed: %d\n", value);
        usleep(1000);
    }
    return NULL;
}

int main() {
    pthread_t prod, cons;
    pthread_create(&prod, NULL, producer, NULL);
    pthread_create(&cons, NULL, consumer, NULL);
    pthread_join(prod, NULL);
    pthread_join(cons, NULL);
    return 0;
}

在这里插入图片描述

第四部分:线程间通信

七、原子操作 Atomic Operations

原子操作可以避免多线程环境下的数据竞争问题。

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

atomic_int counter = ATOMIC_VAR_INIT(0);

void* incrementCounter(void* arg) {
    for (int i = 0; i < 1000000; ++i) {
        atomic_fetch_add_explicit(&counter, 1, memory_order_relaxed);
    }
    return NULL;
}

int main() {
    pthread_t threads[2];
    for (int i = 0; i < 2; ++i) {
        pthread_create(&threads[i], NULL, incrementCounter, NULL);
    }

    for (int i = 0; i < 2; ++i) {
        pthread_join(threads[i], NULL);
    }

    printf("Final count: %d\n", atomic_load_explicit(&counter, memory_order_relaxed));

    return 0;
}
八、信号量 Semaphore

信号量可以用于解决线程间的同步问题。

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

sem_t semaphore;

void* waitOnSemaphore(void* arg) {
    sem_wait(&semaphore);
    printf("Thread got the semaphore\n");
    sleep(1);
    sem_post(&semaphore);
    return NULL;
}

int main() {
    sem_init(&semaphore, 0, 1);
    pthread_t threads[2];
    for (int i = 0; i < 2; ++i) {
        pthread_create(&threads[i], NULL, waitOnSemaphore, NULL);
    }

    for (int i = 0; i < 2; ++i) {
        pthread_join(threads[i], NULL);
    }

    sem_destroy(&semaphore);
    return 0;
}

在这里插入图片描述

第五部分:高级应用

九、线程池 ThreadPool

线程池是一种常见的模式,用于管理一组可复用的线程。

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

#define NUM_THREADS 4

pthread_mutex_t queueLock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t queueNotEmpty = PTHREAD_COND_INITIALIZER;
int queue[100];
int head = 0;
int tail = 0;

typedef struct {
    int id;
} job_t;

void* worker(void* arg) {
    while (1) {
        pthread_mutex_lock(&queueLock);
        while (head == tail) {
            pthread_cond_wait(&queueNotEmpty, &queueLock);
        }
        job_t job = queue[tail];
        tail = (tail + 1) % 100;
        pthread_mutex_unlock(&queueLock);

        printf("Thread %d is working on job %d\n", *((int*)arg), job.id);
        sleep(1);
    }
    return NULL;
}

void addJob(job_t job) {
    pthread_mutex_lock(&queueLock);
    queue[head] = job;
    head = (head + 1) % 100;
    pthread_cond_signal(&queueNotEmpty);
    pthread_mutex_unlock(&queueLock);
}

int main() {
    pthread_t workers[NUM_THREADS];
    for (int i = 0; i < NUM_THREADS; ++i) {
        pthread_create(&workers[i], NULL, worker, &i);
    }

    for (int i = 0; i < 10; ++i) {
        job_t job = {i};
        addJob(job);
    }

    for (int i = 0; i < NUM_THREADS; ++i) {
        pthread_join(workers[i], NULL);
    }

    pthread_mutex_destroy(&queueLock);
    pthread_cond_destroy(&queueNotEmpty);
    return 0;
}

在这里插入图片描述

第六部分:线程生命周期管理

十、线程终止

线程可以通过 pthread_exit() 或者接收到某些信号如 SIGTERM 来终止。

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

void* threadFunction(void* arg) {
    printf("Thread running\n");
    pthread_exit(NULL);
}

int main() {
    pthread_t thread;
    if (pthread_create(&thread, NULL, threadFunction, NULL) == 0) {
        printf("Thread created\n");
        pthread_join(thread, NULL); // 等待线程结束
    }
    return 0;
}
十一、线程分离 Detaching Threads

线程可以被分离(detached),这意味着线程结束后不需要其他线程显式地调用 pthread_join()

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

void* threadFunction(void* arg) {
    printf("Thread running\n");
    pthread_exit(NULL);
}

int main() {
    pthread_t thread;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    if (pthread_create(&thread, &attr, threadFunction, NULL) == 0) {
        printf("Thread created\n");
    }
    pthread_attr_destroy(&attr);
    return 0;
}
十二、线程取消 Cancellation

线程可以通过 pthread_cancel() 来取消,而被取消的线程需要通过 pthread_cleanup_push()pthread_cleanup_pop() 来处理清理工作。

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

void cleanupFunction(void* arg) {
    printf("Cleaning up...\n");
}

void* cancellableThread(void* arg) {
    pthread_cleanup_push(cleanupFunction, NULL);
    for (int i = 0; i < 1000000; ++i) {
        if (pthread_testcancel() == 0) {
            printf("Working...\n");
        }
    }
    pthread_cleanup_pop(0);
    return NULL;
}

int main() {
    pthread_t thread;
    pthread_create(&thread, NULL, cancellableThread, NULL);
    sleep(1); // 让线程运行一会儿
    pthread_cancel(thread);
    pthread_join(thread, NULL);
    return 0;
}

在这里插入图片描述

第七部分:线程同步与并发控制

十三、读写锁 Reader-Writer Locks

读写锁允许多个读线程同时访问资源,但只允许一个写线程访问资源。

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

pthread_rwlock_t lock;
int counter = 0;

void* incrementCounter(void* arg) {
    for (int i = 0; i < 1000000; ++i) {
        pthread_rwlock_wrlock(&lock);
        counter++;
        pthread_rwlock_unlock(&lock);
    }
    return NULL;
}

void* readCounter(void* arg) {
    for (int i = 0; i < 1000000; ++i) {
        pthread_rwlock_rdlock(&lock);
        int value = counter;
        pthread_rwlock_unlock(&lock);
    }
    return NULL;
}

int main() {
    pthread_rwlock_init(&lock, NULL);

    pthread_t threads[4];
    for (int i = 0; i < 2; ++i) {
        pthread_create(&threads[i], NULL, incrementCounter, NULL);
    }
    for (int i = 2; i < 4; ++i) {
        pthread_create(&threads[i], NULL, readCounter, NULL);
    }

    for (int i = 0; i < 4; ++i) {
        pthread_join(threads[i], NULL);
    }

    printf("Final count: %d\n", counter);
    pthread_rwlock_destroy(&lock);

    return 0;
}

在这里插入图片描述

第八部分:线程相关API接口说明

1. pthread_create()
  • 功能:创建一个新的线程。
  • 参数
    • pthread_t *restrict thread: 线程标识符的引用。
    • const pthread_attr_t *restrict attr: 线程属性对象。
    • void *(*start_routine)(void *): 线程的入口点函数。
    • void *restrict arg: 传递给线程函数的参数。
  • 返回值:如果成功返回0,否则返回错误码。
2. pthread_join()
  • 功能:等待一个线程结束。
  • 参数
    • pthread_t thread: 要等待的线程的标识符。
    • void **retval: 如果线程正常退出,则会存放线程函数的返回值。
  • 返回值:如果成功返回0,否则返回错误码。
3. pthread_detach()
  • 功能:分离一个线程。
  • 参数
    • pthread_t thread: 要分离的线程的标识符。
  • 返回值:如果成功返回0,否则返回错误码。
4. pthread_mutex_lock() 和 pthread_mutex_unlock()
  • 功能:分别锁定和解锁一个互斥锁。
  • 参数
    • pthread_mutex_t *mutex: 互斥锁对象。
  • 返回值:如果成功返回0,否则返回错误码。
5. pthread_rwlock_wrlock() 和 pthread_rwlock_unlock()
  • 功能:分别锁定和解锁一个读写锁(写入模式)。
  • 参数
    • pthread_rwlock_t *rwlock: 读写锁对象。
  • 返回值:如果成功返回0,否则返回错误码。
6. pthread_rwlock_rdlock() 和 pthread_rwlock_unlock()
  • 功能:分别锁定和解锁一个读写锁(读取模式)。
  • 参数
    • pthread_rwlock_t *rwlock: 读写锁对象。
  • 返回值:如果成功返回0,否则返回错误码。
7. pthread_cancel()
  • 功能:请求取消指定的线程。
  • 参数
    • pthread_t thread: 要取消的线程的标识符。
  • 返回值:如果成功返回0,否则返回错误码。
8. pthread_testcancel()
  • 功能:测试线程是否已经被请求取消。
  • 返回值:无返回值,如果线程被请求取消,则会抛出异常。
9. pthread_cleanup_push() 和 pthread_cleanup_pop()
  • 功能:用于在取消点之前注册清理函数。
  • 参数
    • void (*routine)(void *): 清理函数。
    • void *arg: 传递给清理函数的参数。

总结

本文详细介绍了线程的基本概念、创建与管理、同步机制、线程间通信、高级应用等多个方面,并提供了丰富的实战示例代码以及对常用线程API接口的说明。通过学习这些知识,你将能够在实际项目中更有效地管理和利用多线程架构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值