1. 简介
Linux线程编程是指在Linux系统上进行多线程编程,利用多线程技术来实现并发操作。多线程编程是现代计算机中广泛使用的技术之一,可以提高系统效率和性能。在编写多线程程序时,需要考虑多个线程之间的同步和互斥问题,以避免线程安全问题的产生。
2. 多线程基础知识
2.1 线程的基本概念
线程是CPU调度的最小单位,同一进程中的线程共享进程的内存空间和全局变量。线程之间的通信和同步要比进程之间的容易得多。
线程的特征包括:
线程有独立的栈空间,用于存放线程的执行环境。
线程共享进程的地址空间和全局变量。
线程共享进程打开的文件、信号等资源。
线程可以看作是轻量级的进程。
2.2 创建线程
在Linux系统中,可以使用pthread库中的函数来创建线程。具体方法是使用pthread_create函数,并在其中传递线程函数的指针和参数。线程函数是被创建的线程所要执行的代码。以下是一个简单的创建线程的示例代码:
#include<stdio.h>
#include<pthread.h>
void *thread_func(void *arg) {
int tid = (int)arg;
printf("Hello from thread %d\n", tid);
pthread_exit(NULL);
}
int main() {
pthread_t tid[2];
int i;
for (i = 0; i < 2; ++i) {
pthread_create(&tid[i], NULL, thread_func, (void *)i);
}
for (i = 0; i < 2; ++i) {
pthread_join(tid[i], NULL);
}
return 0;
}
上述代码中:
使用pthread_create函数创建了两个线程,并将它们的线程ID存储在数组tid中。
每个线程将调用thread_func函数,并传递线程ID作为参数。
在主线程中使用pthread_join函数等待每个线程的结束。
2.3 同步和互斥
多线程编程中,同步和互斥是最常见的问题。同步是指多个线程之间的顺序执行,互斥是指多个线程之间的独占访问。在Linux系统中,可以使用pthread_mutex_lock函数和pthread_mutex_unlock函数来实现对共享资源的互斥访问。以下是一个简单的互斥访问的示例代码:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
pthread_mutex_t mutex;
void *thread_func(void *arg) {
int i, count = (int)arg;
for (i = 0; i < count; ++i) {
pthread_mutex_lock(&mutex);
printf("Thread[%d]: %d\n", (int)pthread_self(), i);
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
int main() {
pthread_t tid[2];
int i;
pthread_mutex_init(&mutex, NULL);
for (i = 0; i < 2; ++i) {
pthread_create(&tid[i], NULL, thread_func, (void *)10);
}
for (i = 0; i < 2; ++i) {
pthread_join(tid[i], NULL);
}
pthread_mutex_destroy(&mutex);
return 0;
}
上述代码中:
使用pthread_mutex_lock函数和pthread_mutex_unlock函数实现了对共享资源的互斥访问。
使用pthread_self函数获取当前线程的线程ID。
在主线程中使用pthread_join函数等待每个线程的结束。
3. 挑战题目
下面是一道多线程编程的挑战题目:
3.1 题目描述
有一组数据,每个数据表示一条边,其中包含起点和终点的坐标(x1, y1)和(x2, y2)。现需要多线程并发计算这些边的长度,输出长度最长的边。
3.2 输入格式
输入数据的第一行是一个整数n,表示边的数量。接下来的n行,每行4个整数x1, y1, x2, y2,表示一个边的起点和终点的坐标。
3.3 输出格式
输出计算出的长度最长的边的起点和终点的坐标(x1, y1)和(x2, y2)。
3.4 要求
使用pthread库实现多线程并发计算;
使用互斥锁来保证计算结果的正确性;
使用条件变量来实现线程间的同步。
3.5 示例
输入:
3
0 0 1 1
1 1 2 2
2 2 3 3
输出:
2.82843 (1.00000, 1.00000) (2.00000, 2.00000)
3.6 参考代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <math.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
int ready = 0;
double max_length = 0;
int max_x1, max_y1, max_x2, max_y2;
typedef struct {
int x1, y1, x2, y2;
} Edge;
void *thread_func(void *arg) {
int i;
double length;
Edge *edges = (Edge *)arg;
for (i = 0; i < 3; ++i) {
length = sqrt(pow(edges[i].x1 - edges[i].x2, 2) + pow(edges[i].y1 - edges[i].y2, 2));
pthread_mutex_lock(&mutex);
if (length > max_length) {
max_length = length;
max_x1 = edges[i].x1;
max_y1 = edges[i].y1;
max_x2 = edges[i].x2;
max_y2 = edges[i].y2;
}
ready++;
if (ready == 3) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
int main() {
pthread_t tid;
int i, n;
Edge edges[3];
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
scanf("%d", &n);
for (i = 0; i < n; ++i) {
scanf("%d%d%d%d", &edges[i % 3].x1, &edges[i % 3].y1, &edges[i % 3].x2, &edges[i % 3].y2);
if (i % 3 == 2) {
pthread_create(&tid, NULL, thread_func, edges);
pthread_mutex_lock(&mutex);
while (ready != 3) pthread_cond_wait(&cond, &mutex);
ready = 0;
pthread_mutex_unlock(&mutex);
pthread_join(tid, NULL);
}
}
if (n % 3 != 0) {
pthread_create(&tid, NULL, thread_func, edges);
pthread_mutex_lock(&mutex);
while (ready != n % 3) pthread_cond_wait(&cond, &mutex);
ready = 0;
pthread_mutex_unlock(&mutex);
pthread_join(tid, NULL);
}
printf("%.5lf (%.5lf, %.5lf) (%.5lf, %.5lf)\n", max_length, (double)max_x1, (double)max_y1, (double)max_x2, (double)max_y2);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return 0;
}
4. 总结
在Linux系统下进行多线程编程是一项常见的技能,掌握多线程编程可以提高程序并发性和运行效率。在编写多线程程序时,我们需要考虑多线程之间的同步和互斥问题以及如何避免线程安全问题的产生。挑战性的多线程编程题目可以帮助我们深入理解多线程编程的基本原理和技术,提高我们的多线程编程技能。