【探索Linux】—— 强大的命令行工具 P.19(多线程 | 线程的概念 | 线程控制 | 分离线程)

在这里插入图片描述

阅读导航

  • 引言
  • 一、 Linux线程概念
    • 1. 什么是线程
    • 2. 线程的概念
    • 3. 线程与进程的区别
    • 4. 线程异常
  • 二、Linux线程控制
    • 1. POSIX线程库
    • 2. 创建线程 pthread_create() 函数
      • (1)头文件
      • (2)函数原型
      • (3)参数解释
      • (4)返回值
      • (5)使用示例
    • 3. 线程ID及进程地址空间布局
      • (1)进程地址空间布局
      • (2)线程ID pthread_self() 函数
    • 4. 线程等待 pthread_join() 函数
      • (1)头文件
      • (2)函数原型
      • (3)参数解释
      • (4)返回值
      • (5)使用示例
    • 5. 线程终止
      • (1)线程终止的三种方法
      • (2)pthread_exit() 函数
      • (3)pthread_cancel() 函数
  • 三、分离线程
    • 1. joinable与线程分离
    • 2. 分离线程 pthread_detach() 函数
      • (1)头文件
      • (2)函数原型
      • (3)参数解释
      • (4)返回值
      • (5)使用示例
  • 四、线程的优缺点
  • 五、线程用途
  • 温馨提示

引言

在当今信息技术日新月异的时代,多线程编程已经成为了日常开发中不可或缺的一部分。Linux作为一种广泛应用的操作系统,其对多线程编程的支持也相当完善。本文将会介绍关于Linux多线程相关的知识,其中包括了线程的概念、线程控制、线程分离等方面的内容。如果你希望提升自己的多线程编程能力,本文将为你提供实用的技术指导和详尽的知识储备。让我们一起来深入了解Linux多线程编程的奥秘吧!

一、 Linux线程概念

1. 什么是线程

  • 在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列”。
  • 一切进程至少都有一个执行线程。
  • 线程在进程内部运行,本质是在进程地址空间内运行。
  • 在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更加轻量化。
  • 透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程执行流。

2. 线程的概念

在Linux中,线程是指在同一个进程内部并发执行的多个子任务。Linux将线程作为轻量级进程(LWP)来实现,每个线程共享相同的进程地址空间和其他资源,包括文件描述符、信号处理器和其他内核状态。由于线程之间共享进程的资源,因此线程之间的切换开销通常比进程之间的切换要小得多。

Linux使用POSIX线程库(pthread)来支持多线程编程。通过pthread库,开发人员可以方便地创建、控制和同步线程,实现多线程编程的各种功能。在Linux中,线程的创建和管理都是通过系统调用和pthread库来完成的,开发人员可以使用pthread_create()函数创建新线程,并使用pthread_join()函数等来等待线程的结束,后面我们会详细介绍。

在Linux中,线程与进程一样拥有自己的ID、寄存器上下文、栈和线程本地存储(TLS)。线程可以通过共享内存进行通信,也可以使用线程同步机制来协调彼此的操作。在多核处理器上,Linux内核会将不同的线程分配到不同的处理器核心上并行执行,以提高系统的性能和响应速度。

总的来说,Linux线程是在同一个进程内并发执行的多个子任务,通过共享进程的资源和使用pthread库来实现线程的创建和管理。在Linux环境下,充分利用线程可以提高程序的并发能力和性能表现。
在这里插入图片描述

3. 线程与进程的区别

Linux线程和进程的主要区别在于它们是操作系统对应不同的执行单元。

  1. 资源分配

    • 进程是资源分配的最小单位,每个进程都有自己的地址空间、全局变量、堆栈、文件描述符等系统资源。
    • 线程是CPU调度的最小单位,多个线程可以共享同一个进程的资源,包括地址空间、全局变量、文件描述符等。
  2. 切换开销

    • 因为线程共享进程资源,因此线程之间的切换开销比进程之间的切换要小得多。
    • 线程的上下文切换只需要保存处理器寄存器和栈指针,而进程切换需要保存整个进程的上下文信息,包括内存映像、堆栈、寄存器等。
  3. 通信机制

    • 进程之间通常使用IPC(Inter-Process Communication)机制来进行进程间通信,例如管道、消息队列、共享内存和信号量等。
    • 线程之间可以通过共享内存、互斥锁、条件变量等同步机制来进行通信和协调。
  4. 并发能力

    • 由于线程共享进程资源和较小的切换开销,因此线程可以更轻松地实现并发执行,提高程序的并发处理能力和性能表现。
  5. 安全性

    • 线程共享进程资源,因此线程之间操作共享数据可能会引起竞态条件等并发问题,需要使用同步机制来协调线程的操作。
    • 进程之间不共享地址空间,可以通过IPC机制来实现安全的进程间通信。

进程和线程的关系如下图
在这里插入图片描述

4. 线程异常

  1. 线程死锁:线程之间相互等待对方释放资源,导致所有线程都无法继续执行的情况。

  2. 竞态条件:多个线程同时访问共享的资源,导致意外的结果或者数据损坏。

  3. 内存泄漏:线程未正确释放动态分配的内存,导致系统资源耗尽。

  4. 线程间通信问题:线程之间的通信出现问题,例如数据丢失、阻塞等情况。

  5. 未捕获的异常:线程中的代码抛出未捕获的异常,导致线程意外终止。

当一个线程出现严重的异常导致崩溃时,会触发进程内的异常处理机制。在大多数操作系统中,异常会导致信号被发送给进程,例如SIGSEGV(段错误)或SIGFPE(浮点异常)。默认情况下,这些信号会终止整个进程。

🚨注意线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出

二、Linux线程控制

1. POSIX线程库

在Linux系统中,POSIX线程库(也称为pthread库)是一套用于多线程编程的标准接口。它基于POSIX标准(Portable Operating System Interface)定义了一组函数和数据类型,使得开发者可以方便地进行多线程程序的开发

POSIX线程库的设计目标是提供一个可移植、高效和可靠的多线程编程接口。它已经成为类UNIX系统上标准的多线程编程接口,并在Linux系统中得到广泛应用。开发者可以使用POSIX线程库编写具有良好可移植性的多线程程序,无需关心底层操作系统的差异

2. 创建线程 pthread_create() 函数

在Linux系统中,线程的创建是通过POSIX线程库(pthread库)提供的函数来实现的

(1)头文件

pthread_create() 函数的使用需要包含pthread库的头文件pthread.h

#include <pthread.h>

(2)函数原型

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

(3)参数解释

  1. thread:指向 pthread_t 类型的指针,用于存储新线程的标识符。在函数成功返回时,该指针被设置为新线程的标识符,可以用于后续操作。

  2. attr:指向 pthread_attr_t 类型的指针,用于设置线程的属性,通常可以传入 nullptr,表示使用默认属性。如果需要设置线程的属性,可以使用 pthread_attr_init() 函数初始化属性对象,并使用 pthread_attr_setxxx() 函数设置属性。

  3. start_routine:指向线程函数的指针,即新线程的执行体。该函数应该以 void* func(void*) 的形式定义,即带有一个 void 类型指针参数,返回一个 void 类型指针。线程函数的返回值将作为线程的退出状态,可以通过 pthread_join() 函数获取。

  4. arg:传递给线程函数的参数,它必须是一个 void 类型指针,开发者需要自行处理类型转换。

(4)返回值

  • 如果成功创建了新线程,则函数返回 0;
  • 如果失败,则返回一个非零值,表示出现了错误。在出错的情况下,可以使用 perror() 函数输出错误信息,也可以使用 strerror() 函数获取错误信息。

(5)使用示例

#include <stdio.h>
#include <pthread.h>void* thread_function(void* arg) {int tid = *(int*)arg;printf("This is thread %d.\n", tid);pthread_exit(NULL);
}int main() {pthread_t tid[3];int i, rc;// 创建三个新线程for (i = 0; i < 3; i++) {rc = pthread_create(&tid[i], NULL, thread_function, (void*)&i);if (rc != 0) {fprintf(stderr, "Failed to create new thread.\n");return 1;}}// 等待所有新线程结束for (i = 0; i < 3; i++) {rc = pthread_join(tid[i], NULL);if (rc != 0) {fprintf(stderr, "Failed to join the thread.\n");return 1;}}printf("All threads exit.\n");return 0;
}

通过上面的步骤,可以在 Linux 系统下成功创建并执行新的线程。需要注意的是,调pthread_create() 函数时传递给线程函数的参数必须是指向整型变量的指针,否则可能会出现不可预期的错误

在这里插入图片描述

3. 线程ID及进程地址空间布局

(1)进程地址空间布局

进程地址空间布局是指操作系统在内存中为每个进程分配的地址空间的布局方式。以下是典型的Linux进程地址空间布局:

  1. 代码段(Text Segment):
    代码段存储了可执行程序的机器指令。它通常是只读的,并且在内存中只有一份,用于所有执行该程序的进程。

  2. 数据段(Data Segment):
    数据段存储了全局变量和静态变量。它包括了初始化的数据和非初始化的BSS段(Block Started by Symbol)。数据段通常是可读写的。

  3. 堆(Heap):
    堆是动态分配内存的区域。在运行时,通过调用malloc()calloc()等函数分配堆内存。堆的大小不固定,可以根据需要动态增长或缩小。

  4. 栈(Stack):
    栈用于存储函数调用、局部变量和函数参数等信息。每个线程都有自己的栈,用于保存线程特定的上下文信息。栈的大小通常是固定的。

  5. 共享库(Shared Libraries):
    共享库存储了被多个进程共享的代码和数据。它们被加载到内存中,并映射到每个进程的地址空间中。

  6. 内核空间(Kernel Space):
    内核空间是由操作系统内核使用的内存区域,不属于进程的地址空间。它包括操作系统内核的代码和数据结构。

在这里插入图片描述

(2)线程ID pthread_self() 函数

线程ID(Thread ID)是操作系统分配给每个线程的唯一标识符。在不同的操作系统中,线程ID的表示方式和取值范围可能会有所不同。
pthread_self()函数是一个POSIX线程库中的函数,用于获取当前线程的线程ID。它的原型如下:

pthread_t pthread_self(void);

该函数没有参数,返回类型为pthread_t,即线程ID的类型

使用pthread_self()函数可以在多线程程序中获取当前线程的线程ID。每个线程在创建时都会被分配一个唯一的线程ID,可以通过该ID来标识和区分不同的线程。

下面是一个简单的示例代码,演示了如何使用pthread_self()函数获取当前线程的线程ID:

#include <stdio.h>
#include <pthread.h>void* thread_func(void* arg) {pthread_t tid = pthread_self();printf("Thread ID: %lu\n", tid);return NULL;
}int main() {pthread_t tid;pthread_create(&tid, NULL, thread_func, NULL);pthread_join(tid, NULL);return 0;
}

在上述示例中,主线程创建了一个新线程,并通过pthread_create()函数启动线程执行thread_func()函数。在thread_func()函数中,调用pthread_self()函数获取当前线程的线程ID,并将其打印输出。

🚨注意线程ID的类型pthread_t可能是一个不透明的数据类型,具体实现取决于操作系统和编译器。在上述示例中,使用%lu格式指定符打印无符号长整型,以与pthread_t类型匹配。在不同的系统和编译环境中,可能需要根据具体情况调整打印格式。
在这里插入图片描述

4. 线程等待 pthread_join() 函数

线程等待是一种同步机制,会导致线程之间的阻塞和等待。在设计多线程程序时,需要合理地安排线程的执行顺序和等待关系,以避免死锁、饥饿等问题pthread_join()函数是一个POSIX线程库中的函数,用于等待指定的线程结束并回收其资源。

(1)头文件

pthread_join() 函数的使用需要包含pthread库的头文件pthread.h

#include <pthread.h>

(2)函数原型

int pthread_join(pthread_t thread, void **retval);

(3)参数解释

  • thread参数是要等待的目标线程的线程ID,
  • retval参数用于接收目标线程的返回值(如果有)。pthread_join()函数会阻塞调用线程,直到目标线程结束为止,并且可以获取目标线程的返回值

(4)返回值

pthread_join() 函数的返回值表示线程的终止状态,具体取值如下:

  • 如果线程的返回值已经被存放到 value_ptr 指向的内存中,则返回 0。
  • 如果指定的线程在执行过程中被取消,则返回 PTHREAD_CANCELED
  • 如果调用该函数时出现错误,则返回相应的错误代码。

(5)使用示例

下面是一个简单的示例代码,演示了如何使用pthread_join()函数等待子线程结束并获取其返回值:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>void* thread_func(void* arg) {int* result = (int*)malloc(sizeof(int));*result = 42;printf("Thread is about to exit\n");pthread_exit((void*)result);  // 终止线程,并返回 result
}int main() {pthread_t tid;void* ret_val;pthread_create(&tid, NULL, thread_func, NULL);pthread_join(tid, &ret_val);  // 获取线程的返回值if (ret_val) {printf("Thread returned: %d\n", *((int*)ret_val));free(ret_val);  // 释放返回值对应的内存} else {printf("Thread returned NULL\n");}return 0;
}

在上面的示例中,我们创建了一个新线程,线程函数中使用了 pthread_exit() 函数来结束线程并返回一个整数值。在主线程中,我们通过 pthread_join() 函数等待线程的终止,并获取了线程的返回值。

🚨注意pthread_join()函数会使调用线程进入阻塞状态,直到目标线程结束。如果不关心目标线程的返回值,也可以将retval参数设置为NULL。另外,在多线程程序中,需要特别注意线程的安全退出和资源回收,以避免产生悬挂线程或资源泄漏的问题。
在这里插入图片描述

5. 线程终止

(1)线程终止的三种方法

  1. 线程函数返回:线程函数执行完毕并从函数中返回,线程会自动终止。线程函数可以通过返回一个值来传递结果给线程的创建者。

  2. 调用 pthread_exit() 函数:线程可以显式地调用 pthread_exit() 函数来终止自己。这个函数接受一个参数作为线程的返回值,可以被其他线程通过调用 pthread_join() 函数获取。

  3. 取消线程:线程可以被其他线程取消。调用 pthread_cancel(pthread_t thread) 函数可以请求取消指定的线程。被取消的线程可以选择在适当的时机终止自己,或者忽略取消请求继续执行。

(2)pthread_exit() 函数

pthread_exit() 函数是用于终止当前线程并返回一个值的 POSIX 线程库函数。该函数的原型如下所示:

void pthread_exit(void* value_ptr);
  • value_ptr:表示线程的返回值,可以是任意类型的指针。当线程调用 pthread_exit() 函数时,会将 value_ptr 指向的内容作为线程的返回值。

pthread_exit() 函数允许线程在执行过程中随时退出,并返回一个值。这个返回值可以被其他线程通过调用 pthread_join() 函数获取,从而实现线程间的数据交互和结果传递。

下面是一个简单的示例,演示了如何在线程中使用 pthread_exit() 函数来结束线程并返回一个值:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>void* thread_func(void* arg) {int* result = (int*)malloc(sizeof(int));*result = 42;printf("Thread is about to exit\n");pthread_exit((void*)result);  // 终止线程,并返回 result
}int main() {pthread_t tid;void* ret_val;pthread_create(&tid, NULL, thread_func, NULL);pthread_join(tid, &ret_val);  // 获取线程的返回值printf("Thread returned: %d\n", *((int*)ret_val));free(ret_val);  // 释放返回值对应的内存return 0;
}

在上面的示例中,我们创建了一个新线程,线程函数中使用了 pthread_exit() 函数来结束线程并返回一个整数值。在主线程中,我们通过 pthread_join() 函数获取了线程的返回值,并打印输出了该值。

(3)pthread_cancel() 函数

pthread_cancel() 函数是 POSIX 线程库中用于取消指定线程的函数。该函数的原型如下所示:

int pthread_cancel(pthread_t thread);
  • thread:表示要取消的线程的标识符。

pthread_cancel() 函数会向指定线程发送一个取消请求,并尝试终止该线程的执行。但是,线程是否会被成功取消取决于多个因素,包括线程自身的取消状态和取消点的设置。

pthread_cancel() 函数只是发送一个取消请求并立即返回,并不能保证目标线程会立即终止。目标线程可以选择忽略取消请求或者在适当的取消点进行处理。

取消点(cancellation point)是线程中的一些特定位置,线程在这些位置上可以检查是否有取消请求,并决定是否终止自己的执行。常见的取消点包括 I/O 操作、阻塞的系统调用等。

如果目标线程成功响应了取消请求,并在取消点终止了执行,那么取消状态将被设置为已取消。可以通过调用 pthread_setcancelstate()pthread_setcanceltype() 函数来控制线程的取消状态和取消类型。

下面是一个示例,演示了如何使用 pthread_cancel() 函数来取消线程的执行:

#include <stdio.h>
#include <pthread.h>void* thread_func(void* arg) {while (1) {// 线程执行的逻辑}return NULL;
}int main() {pthread_t tid;pthread_create(&tid, NULL, thread_func, NULL);// 在主线程中取消子线程的执行pthread_cancel(tid);pthread_join(tid, NULL);  // 等待线程结束return 0;
}

在上面的示例中,我们创建了一个新线程,并在主线程中调用 pthread_cancel() 函数来取消子线程的执行。接着,我们使用 pthread_join() 函数等待子线程的终止。

🚨注意在使用 pthread_cancel() 函数取消线程时,应确保目标线程处于可取消状态,并且在适当的位置设置了取消点。否则,取消请求可能被忽略,导致线程无法正确终止。

三、分离线程

1. joinable与线程分离

“joinable” 和线程分离是两种不同的线程状态。

  • “joinable” 状态的线程是指可以被其他线程显式等待和回收资源的线程。在 POSIX 线程库中,默认情况下,创建的线程是可连接状态(joinable)。可连接状态的线程需要使用 pthread_join() 函数来等待其终止,并获取其返回值(如果有)。
  • 线程分离是指将线程属性设置为分离状态,使得线程在终止时可以自动释放相关资源,而无需等待其他线程显式对其进行回收。分离线程通常用于不需要获取线程返回值或进行线程同步的场景。

2. 分离线程 pthread_detach() 函数

pthread_detach() 函数是 POSIX 线程库中的一个函数,用于将指定线程设置为分离状态,即使该线程在终止时可以自动释放相关资源,而无需等待其他线程显式对其进行回收。

(1)头文件

pthread_detach() 函数的使用需要包含pthread库的头文件pthread.h

#include <pthread.h>

(2)函数原型

int pthread_detach(pthread_t thread);

(3)参数解释

  • thread:表示要设置为分离状态的线程的标识符。

(4)返回值

pthread_detach() 函数的返回值为 0 表示调用成功,返回值为非零表示调用失败。失败的原因可能是参数不正确或者内部出现了错误。

🚨注意线程在被设置为分离状态之前,必须处于可连接状态。否则,pthread_detach() 函数将无法将其设置为分离状态,并返回一个错误码

(5)使用示例

下面是一个示例,演示了如何使用 pthread_detach() 函数将线程设置为分离状态:

#include <stdio.h>
#include <pthread.h>void* thread_func(void* arg) {// 线程执行的逻辑return NULL;
}int main() {pthread_t tid;pthread_create(&tid, NULL, thread_func, NULL);// 将线程设置为分离状态pthread_detach(tid);// 不需要使用 pthread_join() 函数进行回收return 0;
}

在上面的示例中,我们创建了一个新线程,并使用 pthread_detach() 函数将其设置为分离状态。由于该线程已经处于分离状态,因此在主线程中无需使用 pthread_join() 函数进行回收。

四、线程的优缺点

线程是一种轻量级的执行单元,可以在一个进程内并发执行多个任务。线程有以下优点和缺点:

优点

  1. 并发执行:线程允许多个任务同时执行,提高了程序的运行效率和响应速度。可以充分利用多核处理器的计算能力。
  2. 共享数据:线程可以共享同一个进程的内存空间,方便数据之间的共享和通信。不同线程之间可以直接读取和修改同一块内存区域的数据,简化了多任务编程的复杂性。
  3. 资源高效:线程的创建和销毁消耗的资源相对较少,线程切换的开销也较小。相比于进程,线程更加轻量级。
  4. 逻辑清晰:使用线程可以将程序分解成多个独立的执行单元,每个线程负责不同的任务,使得程序的逻辑结构更加清晰、模块化。

缺点

  1. 同步和共享问题:多个线程访问共享数据时需要进行同步操作,以避免数据竞争和不一致的结果。需要使用锁、信号量等机制来保护共享资源,增加了编程的复杂性。
  2. 错误管理困难:线程共享同一进程的内存空间,一个线程对共享资源的错误操作可能会影响其他线程的正常执行,导致难以追踪和调试错误。
  3. 调试和测试复杂:由于线程并发执行,线程之间的交互和调试相对复杂。当程序出现问题时,需要仔细分析各个线程的执行顺序和交互情况,增加了调试和测试的难度。
  4. 资源竞争:多个线程同时访问共享资源时可能引发资源竞争问题,如死锁、饥饿等。需要合理设计和管理线程的同步和互斥机制,以避免资源竞争问题。

五、线程用途

  • 合理的使用多线程,能提高CPU密集型程序的执行效率。
  • 合理的使用多线程,能提高IO密集型程序的用户体验。(如生活中我们一边写代码一边下载开发工具,就是多线程运行的一种表现)

温馨提示

感谢您对博主文章的关注与支持!如果您喜欢这篇文章,可以点赞、评论和分享给您的同学,这将对我提供巨大的鼓励和支持。另外,我计划在未来的更新中持续探讨与本文相关的内容。我会为您带来更多关于Linux以及C++编程技术问题的深入解析、应用案例和趣味玩法等。如果感兴趣的话可以关注博主的更新,不要错过任何精彩内容!

再次感谢您的支持和关注。我们期待与您建立更紧密的互动,共同探索Linux、C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/208628.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微服务链路追踪组件SkyWalking实战

概述 微服务调用存在的问题 串联调用链路&#xff0c;快速定位问题&#xff1b;理清服务之间的依赖关系&#xff1b;微服务接口性能分析&#xff1b;业务流程调用处理顺序&#xff1b; 全链路追踪&#xff1a;对请求源头到底层服务的调用链路中间的所有环节进行监控。 链路…

重新认识Word——样式

重新认识Word Word样式给所有一级标题加上一级标题样式修改标题一样式&#xff0c;符合要求 正文样式标题前的小黑点导航窗格样式的相互复制Word一键转PPT 话说回来&#xff0c;一个程序员平时可能还看不起office全家桶的软件&#xff0c;但是&#xff0c;在实际的生活运用中&a…

人工智能与供应链行业融合:预测算法的通用化与实战化

文章目录 前言供应链预测算法的基本流程统计学习模型与机器学习在供应链预测中的角色深度学习模型在智能供应链中的应用算法融合与应用场景实现后记 前言 随着数字化时代的到来&#xff0c;人工智能已经逐渐成为企业信息化建设的重要手段。特别是在供应链行业&#xff0c;人工…

01-使用Git操作本地库,如初始化本地库,提交工作区文件到暂存区和本地库,查看版本信息,版本切换命令等

Git的使用 概述 Git是一个分布式版本控制工具, 通常用来管理项目中的源代码文件(Java类、xml文件、html页面等)进行管理,在软件开发过程中被广泛使用 Git可以记录文件修改的历史记录并形成备份从而实现代码回溯, 版本切换, 多人协作, 远程备份的功能Git具有廉价的本地库,方便…

微信小程序组件与插件有啥区别?怎么用?

目录 一、微信小程序介绍 二、微信小程序组件 三、微信小程序插件 四、微信小程序组件与插件有啥区别 一、微信小程序介绍 微信小程序是一种基于微信平台的应用程序&#xff0c;它可以在微信客户端内直接运行&#xff0c;无需下载和安装。微信小程序具有轻量、便捷、跨平台…

Linux 进程(三)

Linux进程状态的查看&#xff1a; 这是Linux内核源代码对于进程状态的定义&#xff1a; R运行状态&#xff08;running&#xff09;: 并不意味着进程一定在运行中&#xff0c;它表明进程要么是在运行中要么在运行队列里。 S睡眠状态&#xff08;sleeping): 意味着进程在…

乱序学机器学习——主成分分析法PCA

文章目录 概览PCA核心思想和原理PCA求解算法PCA算法代码实现降维任务代码实现PCA在数据降噪中的应用PCA在人脸识别中的应用主成分分析优缺点和适用条件优点缺点适用条件 概览 PCA核心思想和原理 PCA求解算法 特征向量表示分布的方向&#xff0c;特征值表示沿着个方向分布的程度…

C++ extern的用法详细解析

C编程中&#xff0c;extern是一个非常重要的关键字&#xff0c;它的用途主要是用来声明一个全局变量或者函数。本文将详细解析extern的用法&#xff0c;并通过实例进行详细的解释。 1. extern的基本定义 在C中&#xff0c;extern是一个存储类修饰符&#xff0c;它告诉编译器&…

距离向量路由协议——RIP

目录 动态路由动态路由简介为什么需要动态路由动态路由基本原理路由协议的分类 距离向量路由协议RIPv1RIP简介RIPv1的主要特征RIPv1的基本配置RIPv1配置案例被动接口单播更新使用子网地址 RIPv2RIPv2的基本配置RIPv2配置案例 RIPv2的高级配置与RIPv1的兼容性手工路由汇总触发更…

vue3 + element-plus + ts el-table封装

vue3 element-plus ts el-table封装 博客参考https://blog.csdn.net/weixin_45291937/article/details/125523244 1. 文件位置&#xff08;根据自己的需求&#xff09; 2. 在 custom 文件夹下面 创建 mytable 文件夹 3. 直接上代码 // index.vue<template><div …

工业机器视觉megauging(向光有光)使用说明书(十二,轻量级的visionpro)

关于最后一个工具的介绍&#xff1a;就是这个“相机图像” 我们可以鼠标双击点进去看一看&#xff1a; 在图像上点击&#xff0c;就可以截取一块图像&#xff0c;是可以放大缩小的&#xff0c;这个放大很low&#xff0c;是我以前研究缩放入门时的版本&#xff0c;本想删除&…

wordpress安装之Linux解压缩安装

本次教程是为了让大家少走弯路&#xff0c;可以更直观的去认识我们不懂的知识面。 首先我们安装解压缩的软件 命令如下&#xff1a; yum install -y unzip 上一篇我们讲到传输文件了 这篇我们把传输过来的压缩包解压并进行安装。follow me&#xff01; 我们输入命令 unzi…

BUUCTF 间谍启示录 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 在城际公路的小道上&#xff0c;罪犯G正在被警方追赶。警官X眼看他正要逃脱&#xff0c;于是不得已开枪击中了罪犯G。罪犯G情急之下将一个物体抛到了前方湍急的河流中&#xff0c;便头一歪突然倒地。警官X接近一看&…

C#网络编程(System.Net命名空间和System.Net.Sockets命名空间)

目录 一、System.Net命名空间 1.Dns类 &#xff08;1&#xff09;示例源码 &#xff08;2&#xff09;生成效果 2.IPAddress类 &#xff08;1&#xff09;示例源码 &#xff08;2&#xff09;生成效果 3.IPEndPoint类 &#xff08;1&#xff09; 示例源码 &#xff0…

贪心算法(新坑)

贪心入门 概述&#xff1a; 贪心算法是一种在每一步选择中都采取当前最优解的策略&#xff0c;希望最终能够得到全局最优解的算法。简单来说&#xff0c;它会不断地做出局部最优的选择&#xff0c;相信通过这种选择最终能够达到全局最优。 举个例子来说明。假设你要从一个迷…

一小时玩转【负载均衡】

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

万宾科技可燃气体监测仪科技作用全览

燃气管网在运行过程中经常会遇到燃气管道泄漏的问题&#xff0c;燃气泄漏甚至会引起爆炸&#xff0c;从而威胁人民的生命和财产安全&#xff0c;因此对燃气管网进行定期巡检是十分必要的工作。但是传统的人工巡检已不能满足城市的需要&#xff0c;除了选择增加巡检人员之外&…

微服务实战系列之Redis

前言 云淡天高&#xff0c;落木萧萧&#xff0c;一阵西北风掠过&#xff0c;似寒刀。冬天渐渐变得更名副其实了&#xff0c;“暖冬”的说法有点言过其实了。——碎碎念 微服务实战系列之Cache微服务实战系列之Nginx&#xff08;技巧篇&#xff09;微服务实战系列之Nginx微服务实…

WPF Live Charts2 自学笔记

文章目录 前言实现效果微软平台的历史问题 WPF 项目搭建Nuget添加额外框架添加项目初始化livecharts配置其它LiveCharts2 案例简单案例Demo示例ViewViewModel GPU渲染 Github地址仓库 前言 LiveChart 是C# 上面很受欢迎的统计图 UI控件。最近在学WPFhalcon开发&#xff0c;想想…

【动态规划】LeetCode2552:优化了6版的1324模式

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 动态规划 本题其它解法 C前缀和算法的应用&#xff1a;统计上升四元组 类似题解法 包括题目及代码C二分查找算法&#xff1a;132 模式解法一枚举3C二分查找算法&am…