Linux多线程编程(四)攻略
前言
本文将讲解在Linux环境下进行多线程编程的基本概念、操作方法和注意事项,通过示例代码演示实现多线程的一些常见用法。
基础知识
线程的创建和销毁
线程是轻量级的进程,一个进程可以包含多个线程。线程的创建和销毁都是通过pthread库中的函数来完成的:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
int pthread_join(pthread_t thread, void **retval);
int pthread_cancel(pthread_t thread);
pthread_create
函数用于创建一个线程,并将它开始执行的起始点指定为start_routine
(这个起始点函数必须是void* func(void*)
形式的函数指针)。该函数会返回一个线程ID,存放在thread
中,可以通过该线程ID对线程进行操作。pthread_join
函数用于等待一个线程结束,并获取它的返回值(如果有的话)。如果线程在执行pthread_exit
或返回语句时传入了一个指针,那么这个指针就作为retval
的值传递回来。pthread_cancel
函数用于向线程发送一个取消信号,线程可以在任意时刻响应这个信号并结束运行。
线程的同步
多个线程在共享同一个资源时会出现竞态问题,这时需要使用线程同步机制来保证数据的正确性。常用的线程同步机制有:
- 互斥锁:即mutex,提供对共享资源的互斥访问,防止多个线程同时读写资源。
- 条件变量:即cond,用于线程之间的通信和唤醒。
- 信号量:即sem,用于线程之间的通信和控制并发。
线程的并发
在多线程编程中,线程的并发性是非常重要的,可以通过以下几种方式来提高线程的并发性:
- 减小锁的粒度
- 使用无锁的数据结构
- 增加CPU核心数
- 使用协程等更高级别的并发方式
实战
示例一:使用线程池进行并发处理
下面的示例是使用线程池对多个任务进行并发处理的代码。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
typedef struct job {
void *(*function)(void *);
void *argument;
struct job *next;
} job_t;
typedef struct {
job_t *head;
job_t *tail;
int job_count;
int thread_count;
pthread_mutex_t mutex;
pthread_cond_t condition;
} threadpool_t;
threadpool_t *threadpool_create(int thread_count)
{
threadpool_t *pool = (threadpool_t *)malloc(sizeof(threadpool_t));
pthread_mutex_init(&pool->mutex, NULL);
pthread_cond_init(&pool->condition, NULL);
pool->head = NULL;
pool->tail = NULL;
pool->job_count = 0;
pool->thread_count = thread_count;
for (int i = 0; i < thread_count; i++) {
pthread_t worker;
pthread_create(&worker, NULL, threadpool_worker, pool);
pthread_detach(worker);
}
return pool;
}
int threadpool_add_job(threadpool_t *pool, void *(*function)(void *), void *argument)
{
job_t *new_job = (job_t *)malloc(sizeof(job_t));
new_job->function = function;
new_job->argument = argument;
new_job->next = NULL;
pthread_mutex_lock(&pool->mutex);
if (pool->head == NULL) {
pool->head = new_job;
pool->tail = new_job;
} else {
pool->tail->next = new_job;
pool->tail = new_job;
}
pool->job_count++;
pthread_mutex_unlock(&pool->mutex);
pthread_cond_signal(&pool->condition);
return 0;
}
void *threadpool_worker(void *arg)
{
threadpool_t *pool = (threadpool_t *)arg;
while (1) {
pthread_mutex_lock(&pool->mutex);
while (pool->head == NULL)
pthread_cond_wait(&pool->condition, &pool->mutex);
job_t *job = pool->head;
pool->head = pool->head->next;
if (pool->head == NULL)
pool->tail = NULL;
pool->job_count--;
pthread_mutex_unlock(&pool->mutex);
job->function(job->argument);
free(job);
}
}
void threadpool_destroy(threadpool_t *pool)
{
pthread_mutex_lock(&pool->mutex);
job_t *current = pool->head;
while (current != NULL) {
job_t *next = current->next;
free(current);
current = next;
}
pthread_mutex_unlock(&pool->mutex);
pthread_mutex_destroy(&pool->mutex);
pthread_cond_destroy(&pool->condition);
free(pool);
}
void *task(void *arg)
{
int n = *(int *)arg;
printf("Task %d is running\n", n);
sleep(1);
printf("Task %d is done\n", n);
return NULL;
}
int main()
{
threadpool_t *pool = threadpool_create(4);
int n = 10;
for (int i = 0; i < n; i++)
threadpool_add_job(pool, task, &i);
sleep(10);
threadpool_destroy(pool);
return 0;
}
该代码实现了一个简单的线程池,可以对多个任务进行并发处理。
示例二:使用互斥锁保护共享资源
下面的示例是使用互斥锁保护共享资源的代码。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define THREAD_COUNT 10
int counter = 0;
pthread_mutex_t mutex;
void *increment(void *arg)
{
for (int i = 0; i < 100000; i++) {
pthread_mutex_lock(&mutex);
counter++;
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main()
{
pthread_t threads[THREAD_COUNT];
pthread_mutex_init(&mutex, NULL);
for (int i = 0; i < THREAD_COUNT; i++)
pthread_create(&threads[i], NULL, increment, NULL);
for (int i = 0; i < THREAD_COUNT; i++)
pthread_join(threads[i], NULL);
printf("Counter = %d\n", counter);
pthread_mutex_destroy(&mutex);
return 0;
}
该代码使用互斥锁保护了一个共享变量,避免了多个线程同时读写该变量的产生竞态问题。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:linux多线程编程(四) - Python技术站