自学内容网 自学内容网

C语言线程详解,及Linux中的一些相关命令


以下是关于C语言中线程的详细讲解,包含线程的创建、管理、同步、终止等方面的内容,并增加了对线程和进程的区别与联系的讲解,以及相关知识的扩展。同时,添加了Linux中对线程和进程相关操作的命令。

1. 线程的基本概念

  • 线程:线程是进程中的一个执行流,多个线程共享同一进程的资源(如内存、文件描述符等),可以并发执行。
  • 进程:进程是操作系统分配资源的基本单位,每个进程都有自己的地址空间。线程是轻量级的进程。

2. 线程与进程的区别与联系

2.1 区别
  1. 资源分配

    • 进程:每个进程都有独立的地址空间和资源,进程之间的通信需要通过IPC(进程间通信)机制,如管道、消息队列、共享内存等。
    • 线程:线程共享同一进程的地址空间和资源,线程之间的通信相对简单,可以直接访问共享数据。
  2. 创建和销毁

    • 进程:创建和销毁进程的开销较大,因为需要分配和管理独立的资源。
    • 线程:创建和销毁线程的开销较小,因为线程共享进程的资源。
  3. 调度

    • 进程:操作系统对进程的调度相对复杂,涉及到进程的状态管理和上下文切换。
    • 线程:线程的调度相对简单,线程的上下文切换速度更快。
  4. 稳定性

    • 进程:一个进程的崩溃不会影响其他进程的运行。
    • 线程:一个线程的崩溃可能导致整个进程的崩溃,因为所有线程共享同一进程的资源。
2.2 联系
  • 共享资源:线程是进程的一部分,多个线程可以共享同一进程的资源,如内存和文件描述符。
  • 并发执行:线程和进程都可以实现并发执行,提升程序的性能和响应能力。
  • 调度机制:操作系统对线程和进程的调度机制有相似之处,都是通过调度算法来管理执行。

3. 线程的底层实现

线程的底层实现依赖于操作系统的调度和管理机制。不同的操作系统可能会有不同的线程实现方式,但通常包括以下几个方面:

3.1 线程调度

操作系统使用调度算法来管理线程的执行。常见的调度算法包括:

  • 先来先服务(FCFS):按照线程到达的顺序进行调度。
  • 时间片轮转(Round Robin):为每个线程分配一个时间片,时间片用完后切换到下一个线程。
  • 优先级调度:根据线程的优先级进行调度,高优先级线程优先执行。
3.2 线程上下文切换

当操作系统需要切换执行的线程时,会进行上下文切换。上下文切换的过程包括:

  1. 保存当前线程的上下文(寄存器、程序计数器等)。
  2. 加载下一个线程的上下文。
  3. 更新调度信息。

上下文切换是一个相对昂贵的操作,频繁的上下文切换会影响程序的性能。

3.3 线程栈

每个线程都有自己的栈空间,用于存储局部变量、函数参数和返回地址。线程栈的大小可以在创建线程时指定,通常默认大小为1MB。

4. 线程的创建

在C语言中,线程通常通过POSIX线程(pthread)库来创建和管理。以下是创建线程的基本步骤:

4.1 包含头文件

在使用pthread库之前,需要包含相应的头文件:

#include <pthread.h>
4.2 定义线程函数

线程函数必须返回void*类型,并接受一个void*类型的参数。这个参数可以用来传递数据给线程。

void* thread_function(void* arg) {
    int* num = (int*)arg; // 将参数转换为整数指针
    printf("Thread number: %d\n", *num);
    return NULL;
}
4.3 创建线程

使用pthread_create函数创建线程。该函数的原型如下:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
  • thread:指向线程标识符的指针。
  • attr:线程属性,通常为NULL
  • start_routine:线程执行的函数。
  • arg:传递给线程函数的参数。

示例代码:

int main() {
    pthread_t thread_id;
    int thread_num = 1; // 线程参数
    pthread_create(&thread_id, NULL, thread_function, &thread_num);
    pthread_join(thread_id, NULL); // 等待线程结束
    return 0;
}

5. 线程的同步

由于多个线程可能会同时访问共享资源,因此需要同步机制来避免数据竞争。常用的同步机制包括:

5.1 互斥锁(Mutex)

互斥锁用于保护共享资源,确保同一时间只有一个线程可以访问该资源。使用互斥锁的步骤如下:

  1. 初始化互斥锁

    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);
    
  2. 加锁和解锁

    pthread_mutex_lock(&mutex);
    // 访问共享资源
    pthread_mutex_unlock(&mutex);
    
  3. 销毁互斥锁

    pthread_mutex_destroy(&mutex);
    

示例代码:

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

pthread_mutex_t mutex;

void* thread_function(void* arg) {
    pthread_mutex_lock(&mutex);
    printf("Thread is accessing shared resource.\n");
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main() {
    pthread_t thread_id[5];
    pthread_mutex_init(&mutex, NULL);
    
    for (int i = 0; i < 5; i++) {
        pthread_create(&thread_id[i], NULL, thread_function, NULL);
    }
    
    for (int i = 0; i < 5; i++) {
        pthread_join(thread_id[i], NULL);
    }
    
    pthread_mutex_destroy(&mutex);
    return 0;
}
5.2 条件变量(Condition Variables)

条件变量用于线程之间的信号传递,允许一个线程等待某个条件的发生。使用条件变量的步骤如下:

  1. 初始化条件变量

    pthread_cond_t cond;
    pthread_cond_init(&cond, NULL);
    
  2. 等待条件

    pthread_cond_wait(&cond, &mutex);
    
  3. 发送信号

    pthread_cond_signal(&cond);
    
  4. 销毁条件变量

    pthread_cond_destroy(&cond);
    

示例代码:

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

pthread_mutex_t mutex;
pthread_cond_t cond;
int ready = 0;

void* thread_function(void* arg) {
    pthread_mutex_lock(&mutex);
    while (!ready) {
        pthread_cond_wait(&cond, &mutex);
    }
    printf("Thread is running after condition is met.\n");
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main() {
    pthread_t thread_id;
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);
    
    pthread_create(&thread_id, NULL, thread_function, NULL);
    
    // 模拟一些工作
    sleep(1);
    
    pthread_mutex_lock(&mutex);
    ready = 1; // 设置条件
    pthread_cond_signal(&cond); // 发送信号
    pthread_mutex_unlock(&mutex);
    
    pthread_join(thread_id, NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    return 0;
}

6. 线程的优先级

在C语言中,线程的优先级可以通过pthread_setschedparam函数设置。优先级的管理依赖于操作系统的调度策略。以下是设置线程优先级的示例:

#include <pthread.h>
#include <sched.h>

void* thread_function(void* arg) {
    // 线程执行的代码
    return NULL;
}

int main() {
    pthread_t thread_id;
    pthread_create(&thread_id, NULL, thread_function, NULL);
    
    struct sched_param param;
    param.sched_priority = 10; // 设置优先级
    pthread_setschedparam(thread_id, SCHED_FIFO, &param);
    
    pthread_join(thread_id, NULL);
    return 0;
}

7. 线程的终止

线程可以通过返回线程函数或调用pthread_exit函数来终止。使用pthread_cancel可以请求取消线程,但需要注意线程的状态。

7.1 线程退出
void* thread_function(void* arg) {
    // 执行一些操作
    pthread_exit(NULL); // 线程退出
}
7.2 取消线程
pthread_cancel(thread_id); // 请求取消线程

8. 示例代码

以下是一个完整的示例,展示了如何创建和使用线程,包括互斥锁和条件变量的使用:

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

pthread_mutex_t mutex;
pthread_cond_t cond;
int ready = 0;

void* thread_function(void* arg) {
    pthread_mutex_lock(&mutex);
    while (!ready) {
        pthread_cond_wait(&cond, &mutex);
    }
    printf("Thread is running after condition is met.\n");
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main() {
    pthread_t thread_id;
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);
    
    pthread_create(&thread_id, NULL, thread_function, NULL);
    
    // 模拟一些工作
    sleep(1);
    
    pthread_mutex_lock(&mutex);
    ready = 1; // 设置条件
    pthread_cond_signal(&cond); // 发送信号
    pthread_mutex_unlock(&mutex);
    
    pthread_join(thread_id, NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    return 0;
}

9. Linux中对线程和进程相关操作的命令

9.1 查看进程
  • ps aux:查看当前系统中所有进程的信息。
  • top:实时查看系统中进程的资源使用情况。
9.2 查看线程
  • ps -eLf:查看系统中所有线程的信息。
  • top -H:在top命令中显示线程信息。
9.3 杀死进程
  • kill <pid>:发送信号终止指定进程。
  • kill -9 <pid>:强制终止指定进程。
9.4 杀死线程
  • 线程通常通过终止其所属的进程来结束,使用kill命令时指定进程ID(PID)即可。
9.5 创建进程
  • fork():在C语言中使用fork()系统调用创建新进程。
9.6 创建线程
  • pthread_create():在C语言中使用pthread_create()函数创建新线程。

10. 总结

C语言中的线程提供了并发执行的能力,通过使用pthread库,可以创建、管理和同步线程。理解线程的基本概念和操作是编写高效多线程程序的关键。线程与进程的区别在于资源分配、创建和销毁的开销、调度复杂性等方面,而它们之间的联系则体现在共享资源和并发执行的能力上。线程的底层实现涉及调度、上下文切换和线程栈等方面,掌握这些知识有助于更深入地理解多线程编程的性能和行为。线程的同步机制(如互斥锁和条件变量)是确保数据一致性和避免竞争条件的重要工具。Linux中提供了多种命令来管理和监控进程与线程,帮助开发者更好地进行系统调试和性能优化。


原文地址:https://blog.csdn.net/weixin_65477256/article/details/142145440

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!