1. Linux 线程概念简介
在计算机科学中,线程是指进程内的一个执行单元。一个进程可以拥有多个线程,每个线程都有自己的代码执行流和栈。在操作系统中,线程被视为最小的可调度单位,不同于进程的独立内存空间,线程之间共享进程的内存空间。因此,线程的创建和上下文切换要比进程更加高效,能够更好地发挥多核处理器的能力。
1.1 线程的优点
线程在操作系统中扮演着非常重要的角色,主要有以下几个优点:
更高的执行效率:相较于进程,线程的创建和上下文切换的开销更小,能够更快地完成任务。
更好的资源利用:线程之间共享进程的内存空间,能够通过直接读写内存来共享数据,无需进行复杂的进程间通信。
更好的响应性:线程能够使程序更加灵活和响应快速的操作。
1.2 线程的创建
在 Linux 中,线程的创建通常使用 pthread 库来实现,可以通过调用 pthread_create() 函数来创建新的线程。
#include <pthread.h>
void* thread_function(void* arg) {
// 线程的执行逻辑
return NULL;
}
int main() {
pthread_t thread_id;
int result = pthread_create(&thread_id, NULL, thread_function, NULL);
if (result != 0) {
printf("Error creating thread\n");
return 1;
}
// 等待线程执行完成
pthread_join(thread_id, NULL);
return 0;
}
上述代码演示了如何在 Linux 中创建一个新的线程。通过调用 pthread_create() 函数,可以创建一个新的线程,并传入相关的参数。在新线程中执行逻辑的函数需要满足以下条件:
参数类型必须是 void*,表示不定类型的指针。
函数返回类型必须是 void*,表示线程的返回值。
2. Linux 线程的同步
在多线程程序中,由于线程之间共享进程的内存空间,可能会出现多个线程同时访问共享资源的情况,从而导致数据竞争和不一致的问题。为了解决这类问题,需要使用线程的同步机制来保护共享资源。
2.1 互斥锁
互斥锁(Mutex)是一种最常用的线程同步机制,其作用是保护共享资源,使得同一时刻只有一个线程可以访问该资源。在 Linux 中,可以使用 pthread_mutex_t 结构体来表示互斥锁,相关的操作函数包括 pthread_mutex_init()、pthread_mutex_lock()、pthread_mutex_unlock() 和 pthread_mutex_destroy()。
#include <pthread.h>
pthread_mutex_t mutex;
int shared_resource = 0;
void* thread_function(void* arg) {
pthread_mutex_lock(&mutex);
shared_resource += 1;
pthread_mutex_unlock(&mutex);
return NULL;
}
int main() {
pthread_t thread_id[10];
pthread_mutex_init(&mutex, NULL);
for (int i = 0; i < 10; i++) {
pthread_create(&thread_id[i], NULL, thread_function, NULL);
}
for (int i = 0; i < 10; i++) {
pthread_join(thread_id[i], NULL);
}
pthread_mutex_destroy(&mutex);
return 0;
}
上述代码演示了使用互斥锁保护共享资源的使用方法。通过调用 pthread_mutex_lock() 和 pthread_mutex_unlock() 函数来对互斥锁进行加锁和解锁操作,从而保证同一时刻只有一个线程能够修改共享资源。
2.2 读写锁
互斥锁在保护共享资源时具有较高的开销,因为任何一个线程在修改共享资源时都需要获得互斥锁的独占访问权。对于一些读多写少的场景,可以使用读写锁(ReadWrite Lock)来提高效率。
#include <pthread.h>
pthread_rwlock_t rwlock;
int shared_resource = 0;
void* reader_thread(void* arg) {
pthread_rwlock_rdlock(&rwlock);
// 读取共享资源
pthread_rwlock_unlock(&rwlock);
return NULL;
}
void* writer_thread(void* arg) {
pthread_rwlock_wrlock(&rwlock);
// 修改共享资源
pthread_rwlock_unlock(&rwlock);
return NULL;
}
int main() {
pthread_t reader_id[10];
pthread_t writer_id[2];
pthread_rwlock_init(&rwlock, NULL);
for (int i = 0; i < 10; i++) {
pthread_create(&reader_id[i], NULL, reader_thread, NULL);
}
for (int i = 0; i < 2; i++) {
pthread_create(&writer_id[i], NULL, writer_thread, NULL);
}
for (int i = 0; i < 10; i++) {
pthread_join(reader_id[i], NULL);
}
for (int i = 0; i < 2; i++) {
pthread_join(writer_id[i], NULL);
}
pthread_rwlock_destroy(&rwlock);
return 0;
}
上述代码演示了使用读写锁保护共享资源的使用方法。通过调用 pthread_rwlock_rdlock()、pthread_rwlock_wrlock() 和 pthread_rwlock_unlock() 函数来对读写锁进行加锁和解锁操作,从而保证读线程之间可以共享读取资源,写线程独占访问资源。
3. Linux 中的线程调度
在 Linux 中,线程的调度由内核负责。操作系统根据一定的调度策略和优先级来决定下一个要执行的线程。常见的调度策略有先进先出(FIFO)、时间片轮转(Round Robin)等。
3.1 线程优先级
Linux 系统中,每个线程都有一个优先级,优先级越高的线程被调度执行的概率就越大。线程的优先级范围为 0-99,其中0表示最高优先级,99表示最低优先级。可以使用 pthread_setschedparam() 函数来设置线程的优先级。
#include <pthread.h>
#include <sched.h>
void* thread_function(void* arg) {
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(), &policy, ¶m);
printf("Thread priority: %d\n", param.sched_priority);
return NULL;
}
int main() {
pthread_t thread_id;
pthread_attr_t thread_attr;
struct sched_param param;
pthread_attr_init(&thread_attr);
pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);
param.sched_priority = 20;
pthread_attr_setschedparam(&thread_attr, ¶m);
pthread_create(&thread_id, &thread_attr, thread_function, NULL);
pthread_join(thread_id, NULL);
pthread_attr_destroy(&thread_attr);
return 0;
}
上述代码演示了设置线程优先级的使用方法。通过设置线程属性来指定线程的调度策略和优先级,然后通过 pthread_create() 函数创建线程,最后通过 pthread_attr_destroy() 函数销毁线程属性。
3.2 线程亲和性
线程亲和性是指线程与处理器之间的绑定关系。通过将线程绑定到特定的处理器核心上,可以提高线程的局部性以及缓存利用率。
#include <pthread.h>
#include <sched.h>
void* thread_function(void* arg) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(0, &cpuset);
int result = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (result != 0) {
printf("Failed to set thread affinity\n");
}
return NULL;
}
int main() {
pthread_t thread_id;
pthread_create(&thread_id, NULL, thread_function, NULL);
pthread_join(thread_id, NULL);
return 0;
}
上述代码演示了设置线程亲和性的使用方法。通过调用 pthread_setaffinity_np() 函数将线程绑定到指定的处理器核心上,从而保证线程始终在同一个处理器核心上运行。
4. 总结
通过本文的介绍,我们对 Linux 线程的概念及相关知识有了更加深入的了解。线程作为进程内的执行单元,能够更好地发挥计算机的性能。同时,线程的同步、调度和亲和性等特性使得多线程编程变得更加灵活和高效。