C语言中线程的使用

1、什么是线程

线程是操作系统能够进行运算调度的最小单位,它是比进程更小的执行单元,存在于进程之内,是进程中的实际运作单位。一个进程可以包含一个或多个线程,每个线程都执行着进程代码段中的某个函数,但它们共享进程的大部分资源,如内存空间、打开的文件和全局变量,而每个线程拥有自己独立的调用栈、寄存器环境和线程本地存储(Thread Local Storage, TLS)。

线程的主要特点包括:

  1. 轻量化:线程相比于进程,切换成本更低,因为它们共享相同的地址空间,不需要像进程那样复制整个地址空间。

  2. 并发性:线程允许在同一进程中并行执行多个任务,这样可以利用多核处理器的并行计算能力,提高程序的执行效率。

  3. 通信便捷:由于线程共享进程资源,它们之间的通信比进程间通信更容易且开销更小。

  4. 独立调度:线程可以独立于其他线程被调度和执行。

  5. 生命周期:线程有其生命周期,包括创建、就绪、运行、阻塞和终止等状态。

根据线程的管理和调度方式,线程可以分为内核线程(Kernel Thread)、用户线程(User Thread)和混合线程(Hybrid Thread)。内核线程由操作系统内核直接管理和调度,用户线程则完全由用户级的线程库管理,而混合线程则是前两者的结合。

线程的类型包括:

  • 主线程(Main Thread):是程序启动时操作系统创建的第一个线程。
  • 子线程(Child Thread):是程序中创建的除主线程外的其他线程。
  • 守护线程(Daemon Thread):在后台运行,为其他线程提供服务,当所有非守护线程结束时,守护线程也会自动结束。
  • 前台线程(Foreground Thread):相对于守护线程,是指程序中执行主要功能的线程。

2、包含的头文件

#include <pthread.h>

3、常用函数及参数详解

3.1、创建线程函数pthread_create

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine)(void *), void *arg);
  • pthread_t *thread: 指向一个pthread_t类型的指针,用于存储新创建的线程的标识符。
  • const pthread_attr_t *attr: 线程属性对象的指针,可以用来设置线程的各种属性。如果为NULL,则使用默认属性。
  • void *(*start_routine)(void *): 线程函数的指针,即线程开始执行的函数地址。这个函数应该接受一个void *类型的参数,并返回一个void *类型的值。
  • void *arg: 传递给start_routine函数的参数。

3.2、等待线程结束pthread_join()

int pthread_join(pthread_t thread, void **retval);
  • pthread_t thread: 要等待的线程的标识符。
  • void **retval: 如果非NULL,则用于存储线程函数的返回值。

3.3、终止线程执行pthread_exit()

void pthread_exit(void *retval);

void *retval: 线程函数的返回值,可以被其他线程通过pthread_join()获取。

3.4、线程分离pthread_detach()

int pthread_detach(pthread_t thread);

参数thread是要分离的线程的标识符。如果函数成功分离了线程,返回值为0;如果失败,则返回一个错误码。

3.5、代码示例

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

// 线程函数,每个线程将执行此函数
void* thread_function(void* arg) {
    int thread_num = *(int*)arg; // 获取线程编号
    printf("Hello from thread %d\n", thread_num);

    // 释放传入的参数,避免内存泄漏
    free(arg);

    // 线程执行完毕后调用 pthread_exit(),传递退出状态
    pthread_exit(NULL);
}

int main() {
    pthread_t threads[5]; // 创建一个数组来存储5个线程的ID
    int *thread_ids[5]; // 创建一个数组来存储线程ID的指针,作为线程函数的参数

    // 循环创建5个线程
    for (int i = 0; i < 5; ++i) {
        thread_ids[i] = malloc(sizeof(int)); // 为每个线程分配一个整数大小的内存
        *thread_ids[i] = i + 1; // 设置线程编号

        // 调用 pthread_create() 创建线程
        // 参数1: 存储新线程ID的变量
        // 参数2: 线程属性(可选,通常使用NULL表示使用默认属性)
        // 参数3: 线程函数
        // 参数4: 传给线程函数的参数
        if (pthread_create(&threads[i], NULL, thread_function, thread_ids[i]) != 0) {
            perror("Error creating thread");
            exit(EXIT_FAILURE);
        }
    }

    // 对前两个线程使用 pthread_join() 等待它们结束
    for (int i = 0; i < 2; ++i) {
        if (pthread_join(threads[i], NULL) != 0) {
            perror("Error joining thread");
            exit(EXIT_FAILURE);
        }
    }

    // 对剩下的线程使用 pthread_detach() 进行分离,让它们独立运行
    for (int i = 2; i < 5; ++i) {
        if (pthread_detach(threads[i]) != 0) {
            perror("Error detaching thread");
            exit(EXIT_FAILURE);
        }
    }

    printf("Main thread continues...\n");

    return 0;
}
  • 线程函数 thread_function(): 每个线程将执行这个函数。它接受一个void*类型的参数,通常用来传递任意类型的数据。在这个例子中,我们传递了一个指向整数的指针,代表线程的编号。

  • pthread_create(): 用于创建新线程。它接收四个参数:新线程的ID(将被存储在第一个参数所指向的变量中)、线程属性(通常使用NULL表示使用默认属性)、线程函数的指针、以及传递给线程函数的参数。

  • pthread_join(): 用于等待一个线程的结束。当主线程调用pthread_join()并传入一个线程ID时,主线程将阻塞直到指定线程结束。

  • pthread_detach(): 用于分离线程。分离后的线程将在没有主线程等待的情况下独立运行至结束。这意味着分离线程的资源将由系统自动回收,无需主线程显式调用pthread_join()

  • pthread_exit(): 当线程执行完毕时调用,相当于线程的return语句。在这个例子中,我们传递NULL作为线程的退出状态,表示线程正常结束。

  • 30
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值