【LinuxC】C语言线程(pthread)

文章目录

  • 一、 POSIX 线程库
    • 1.1 POSIX标准
    • 1.2 Pthreads
    • 1.2 数据类型、函数、宏
      • 1.21 数据类型
      • 1.22 函数
      • 1.23 宏
  • 二、创建线程
  • 三、线程同步
  • 四、线程销毁
  • 五、示例
    • 5.1 完整示例
    • 5.2 信号量示例

本专栏上一篇文章是Windows下(MSVC)的线程编程,需要的自行查看。
【C语言】Windows下的C语言线程编程详解

进程:进程是操作系统分配资源的基本单位,每个进程有独立的地址空间,进程间通信需要通过特定的机制。
线程:线程是进程中的一个执行单元,它们共享进程的资源。线程之间的切换比进程之间的切换代价小,因此线程编程可以提高程序的并发性能。
并发与并行:并发是指多个任务在同一时间段内交替执行,而并行是指多个任务在同一时刻同时执行。线程编程可以实现并发执行,但是否能够实现并行执行取决于系统的处理器数量和调度策略。

一、 POSIX 线程库

1.1 POSIX标准

POSIX标准是一系列确保操作系统之间兼容性的规范,旨在提升软件的可移植性

POSIX,全称为Portable Operating System Interface,即“可移植操作系统接口”,是由IEEE计算机协会制定的标准。它的主要目的是定义一套操作系统应该遵循的规则和接口,以保证在不同的操作系统之间能够运行相同的程序,而无需或只需很少的修改

POSIX标准涵盖了很多方面,包括系统调用、命令行 shell、文件系统接口、线程等。这些标准允许开发者编写的程序能够在支持POSIX的任何操作系统上运行,从而提高了软件的可移植性和互操作性。

总的来说,POSIX标准是Unix和类Unix系统(如Linux、MacOS)设计的核心部分,它通过提供一致的编程接口,帮助确保应用程序的可移植性和兼容性。

注意标准和实现的区别。POSIX标准主要由C语言实现,而C语言标准则主要关注语言本身的特性。

1.2 Pthreads

POSIX线程(英语:POSIX Threads,常被缩写为pthreads)是POSIX的线程标准,定义了创建和操纵线程的一套API。

实现POSIX线程标准的库常被称作pthreads,一般用于Unix-like POSIX系统,如Linux、 Solaris。但是Microsoft Windows上的实现也存在,例如直接使用Windows API实现的第三方库pthreads-w32;而利用Windows的SFU/SUA子系统,则可以使用微软提供的一部分原生POSIX API。

Pthreads定义了一套C语言的类型、函数与常量,它以pthread.h头文件和一个线程库实现。

Pthreads API中大致共有100个函数调用,全都以"pthread_"开头,并可以分为四类:

  • 线程管理,例如创建线程,等待(join)线程,查询线程状态等。
  • 互斥锁(Mutex):创建、摧毁、锁定、解锁、设置属性等操作
  • 条件变量(Condition Variable):创建、摧毁、等待、通知、设置与查询属性等操作
  • 使用了互斥锁的线程间的同步管理

POSIX的Semaphore API(包含在semaphore.h中)可以和Pthreads协同工作,但这并不是Pthreads的标准。因而这部分API是以"sem_“打头,而非"pthread_”。

1.2 数据类型、函数、宏

1.21 数据类型

  • pthread_t:线程句柄(Windows叫句柄,Linux叫标识符,知道即可)。它是一个结构体数据类型,用于唯一标识一个线程。出于移植目的,不能把它作为整数处理,应使用函数pthread_equal()对两个线程ID进行比较。获取自身所在线程id使用函数pthread_self()。

  • pthread_attr_t:线程属性。主要包括scope属性、detach属性、堆栈地址、堆栈大小、优先级。主要属性的意义如下:

    • __detachstate,表示新线程是否与进程中其他线程脱离同步。如果设置为PTHREAD_CREATE_DETACHED,则新线程不能用pthread_join()来同步,且在退出时自行释放所占用的资源。缺省为PTHREAD_CREATE_JOINABLE状态。可以在线程创建并运行以后用pthread_detach()来设置。一旦设置为PTHREAD_CREATE_DETACHED状态,不论是创建时设置还是运行时设置,则不能再恢复到PTHREAD_CREATE_JOINABLE状态。
    • __schedpolicy,表示新线程的调度策略,包括SCHED_OTHER(正常、非实时)、SCHED_RR(实时、轮转法)和SCHED_FIFO(实时、先入先出)三种,缺省为SCHED_OTHER,后两种调度策略仅对超级用户有效。运行时可以用过pthread_setschedparam()来改变。
    • __schedparam,一个struct sched_param结构,目前仅有一个sched_priority整型变量表示线程的运行优先级。这个参数仅当调度策略为实时(即SCHED_RR或SCHED_FIFO)时才有效,并可以在运行时通过pthread_setschedparam()函数来改变,缺省为0。系统支持的最大和最小的优先级值可以用函数sched_get_priority_max和sched_get_priority_min得到。
    • __inheritsched,有两种值可供选择:PTHREAD_EXPLICIT_SCHED和PTHREAD_INHERIT_SCHED,前者表示新线程使用显式指定调度策略和调度参数(即attr中的值),而后者表示继承调用者线程的值。缺省为PTHREAD_EXPLICIT_SCHED。
    • __scope,表示线程间竞争CPU的范围,也就是说线程优先级的有效范围。POSIX的标准中定义了两个值:PTHREAD_SCOPE_SYSTEM和PTHREAD_SCOPE_PROCESS,前者表示与系统中所有线程一起竞争CPU时间,后者表示仅与同进程中的线程竞争CPU。目前LinuxThreads仅实现了PTHREAD_SCOPE_SYSTEM一值。
  • pthread_mutex_t:互斥锁的类型,用于保护共享资源免受多个线程的同时访问。

  • pthread_cond_t:条件变量的类型,用于线程间的同步,允许线程等待某个特定条件的发生。。

  • pthread_rwlock_t:读写锁的类型,允许多个线程同时读取共享资源,但只允许一个线程写入。

1.22 函数

线程操纵函数(简介起见,省略参数):

  • pthread_create():创建一个线程
  • pthread_exit():终止当前线程
  • pthread_cancel():请求中断另外一个线程的运行。被请求中断的线程会继续运行,直至到达某个取消点(Cancellation Point)。取消点是线程检查是否被取消并按照请求进行动作的一个位置。POSIX 的取消类型(Cancellation Type)有两种,一种是延迟取消(PTHREAD_CANCEL_DEFERRED),这是系统默认的取消类型,即在线程到达取消点之前,不会出现真正的取消;另外一种是异步取消(PHREAD_CANCEL_ASYNCHRONOUS),使用异步取消时,线程可以在任意时间取消。系统调用的取消点实际上是函数中取消类型被修改为异步取消至修改回延迟取消的时间段。几乎可以使线程挂起的库函数都会响应CANCEL信号,终止线程,包括sleep、delay等延时函数。
  • pthread_join():阻塞当前的线程,直到另外一个线程运行结束
  • pthread_kill():向指定ID的线程发送一个信号,如果线程不处理该信号,则按照信号默认的行为作用于整个进程。信号值0为保留信号,作用是根据函数的返回值判断线程是不是还活着。
  • pthread_cleanup_push():线程可以安排异常退出时需要调用的函数,这样的函数称为线程清理程序,线程可以创建多个清理程序。线程清理程序的入口地址使用栈保存,实行先进后处理原则。由pthread_cancel或pthread_exit引起的线程结束,会次序执行由pthread_cleanup_push压入的函数。线程函数执行return语句返回不会引起线程清理程序被执行。
  • pthread_cleanup_pop():以非0参数调用时,引起当前被弹出的线程清理程序执行。
  • pthread_setcancelstate():允许或禁止取消另外一个线程的运行。
  • pthread_setcanceltype():设置线程的取消类型为延迟取消或异步取消。

线程属性函数:

  • pthread_attr_init():初始化线程属性变量。运行后,pthread_attr_t结构所包含的内容是操作系统支持的线程的所有属性的默认值。
  • pthread_attr_setdetachstate():设置线程属性变量的detachstate属性(决定线程在终止时是否可以被joinable)
  • pthread_attr_getdetachstate():获取脱离状态的属性
  • pthread_attr_setscope():设置线程属性变量的__scope属性
  • pthread_attr_setschedparam():设置线程属性变量的schedparam属性,即调用的优先级。
  • pthread_attr_getschedparam():获取线程属性变量的schedparam属性,即调用的优先级。
  • pthread_attr_destroy():删除线程的属性,用无效值覆盖

互斥锁函数:

  • pthread_mutex_init() 初始化互斥锁
  • pthread_mutex_destroy() 删除互斥锁
  • pthread_mutex_lock():占有互斥锁(阻塞操作)
  • pthread_mutex_trylock():试图占有互斥锁(不阻塞操作)。即,当互斥锁空闲时,将占有该锁;否则,立即返回。
  • pthread_mutex_unlock(): 释放互斥锁
  • pthread_mutexattr_(): 互斥锁属性相关的函数

条件变量函数:

  • pthread_cond_init():初始化条件变量
  • pthread_cond_destroy():销毁条件变量
  • pthread_cond_signal(): 发送一个信号给正在当前条件变量的线程队列中处于阻塞等待状态的线程,使其脱离阻塞状态,唤醒后继续执行。如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。一般只给一个阻塞状态的线程发信号。假如有多个线程正在阻塞等待当前条件变量,则根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但pthread_cond_signal在多处理器上可能同时唤醒多个线程,当只能让一个被唤醒的线程处理某个任务时,其它被唤醒的线程就需要继续wait。POSIX规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上的线程,有些实现为了简便,在单处理器上也会唤醒多个线程。所以最好对pthread_cond_wait()使用while循环对条件变量是否满足做条件判断。
  • pthread_cond_wait(): 等待条件变量的特殊条件发生;pthread_cond_wait() 必须与一个pthread_mutex配套使用。该函数调用实际上依次做了3件事:对当前pthread_mutex解锁、把当前线程挂起到当前条件变量的线程队列、被其它线程的信号唤醒后对当前pthread_mutex申请加锁。如果线程收到一个信号被唤醒,将被配套的互斥锁重新锁住,pthread_cond_wait() 函数将不返回直到线程获得配套的互斥锁。需要注意的是,一个条件变量不应该与多个互斥锁配套使用。
  • pthread_cond_broadcast(): 某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.
  • pthread_condattr_(): 条件变量属性相关的函数

线程私有存储(Thread-local storage):

  • pthread_key_create(): 分配用于标识进程中线程特定数据的pthread_key_t类型的键
  • pthread_key_delete(): 销毁现有线程特定数据键
  • pthread_setspecific(): 为指定线程的特定数据键设置绑定的值
  • pthread_getspecific(): 获取调用线程的键绑定值,并将该绑定存储在 value 指向的位置中

同步屏障函数

  • pthread_barrier_init(): 同步屏障初始化
  • pthread_barrier_wait():
  • pthread_barrier_destory():

其它多线程同步函数:

  • pthread_rwlock_*(): 读写锁

工具函数:

  • pthread_equal(): 对两个线程的线程标识号进行比较
  • pthread_detach(): 分离线程
  • pthread_self(): 查询线程自身线程标识号
  • pthread_once(): 某些需要仅执行一次的函数。其中第一个参数为pthread_once_t类型,是内部实现的互斥锁,保证在程序全局仅执行一次。

信号量函数,包含在semaphore.h中:

  • sem_init:用于初始化一个无名信号量。它需要三个参数:一个指向信号量对象的指针、一个表示信号量是否在多个进程间共享的标志,以及信号量的初始值。
  • sem_post:用于增加信号量的值,通常在释放资源时调用。它需要一个指向信号量对象的指针作为参数。
  • sem_wait:用于减少信号量的值,通常在请求资源时调用。如果信号量的值为0,调用此函数的线程将会被阻塞,直到信号量的值大于0。
  • sem_trywait:与sem_wait类似,但它是非阻塞的。如果信号量的值为0,它不会阻塞线程,而是立即返回。
  • sem_getvalue:用于获取信号量的当前值。它需要一个指向信号量对象的指针和一个用于存储信号量值的指针作为参数。
  • sem_destroy:用于销毁一个无名信号量。它需要一个指向信号量对象的指针作为参数。

共享内存函数,包含在sys/mman.h中,链接时使用rt库:

  • mmap:把一个文件或一个POSIX共享内存区对象映射到调用进程的地址空间。使用该函数的目的: 1.使用普通文件以提供内存映射I/O 2.使用特殊文件以提供匿名内存映射。 3.使用shm_open以提供无亲缘关系进程间的Posix共享内存区。
  • munmap: 删除一个映射关系
  • msync:文件与内存同步函数
  • shm_open:创建或打开共享内存区
  • shm_unlink:删除一个共享内存区对象的名字,删除一个名字仅仅防止后续的open,msq_open或sem_open调用获取成功。
  • ftruncate:调整文件或共享内存区大小
  • fstat来获取有关该对象的信息

1.23 宏

  • PTHREAD_CREATE_JOINABLE:创建的线程可以被其他线程回收资源。
  • PTHREAD_CREATE_DETACHED:创建的线程是分离的,不需要其他线程回收资源。
  • PTHREAD_CANCEL_ENABLE:允许取消。
  • PTHREAD_CANCEL_DISABLE:禁止取消。
  • PTHREAD_PROCESS_PRIVATE:线程特定数据只在创建它的进程内可见。
  • PTHREAD_PROCESS_SHARED:线程特定数据可以在不同进程间共享。
  • PTHREAD_MUTEX_INITIALIZER:静态初始化互斥锁。
  • PTHREAD_COND_INITIALIZER:静态初始化条件变量。

二、创建线程

(1)定义线程函数:

线程函数是线程执行的入口点,它的定义形式如下:

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

这个函数的参数和返回值类型都必须是void*

(2)创建线程:

使用pthread_create函数创建线程,函数原型如下:

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

参数说明:

  • thread:指向线程标识符的指针,用于存储新创建的线程ID。
  • attr:指向线程属性的指针,用于设置线程的属性,如堆栈大小、调度策略等。如果设置为NULL,则使用默认属性。
  • start_routine:线程函数的起始地址。
  • arg:传递给线程函数的参数。

(3)等待线程结束:

使用pthread_join函数等待线程结束,函数原型如下:

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

参数说明:

  • thread:要等待的线程ID。
  • retval:用于存储线程函数的返回值。

例:

pthread_t tid; // 线程ID
pthread_create(&tid, NULL, myThreadFunction, NULL);

三、线程同步

前一篇文章讲了线程同步的方式。这里以互斥锁为例。

互斥锁(Mutex):互斥锁是一种用于保护共享资源的机制,确保同一时刻只有一个线程可以访问共享资源。pthread库提供了pthread_mutex_t类型的互斥锁。

  • 初始化互斥锁:使用pthread_mutex_init函数初始化互斥锁。
  • 锁定互斥锁:使用pthread_mutex_lock函数锁定互斥锁。
  • 解锁互斥锁:使用pthread_mutex_unlock函数解锁互斥锁。
  • 销毁互斥锁:使用pthread_mutex_destroy函数销毁互斥锁。

(1)定义和初始化互斥锁:

pthread_mutex_t mutex; // 定义互斥锁变量
  • 静态初始化:使用 PTHREAD_MUTEX_INITIALIZER 宏,这种方式初始化的互斥锁是静态的,不能销毁。
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 静态初始化
  • 动态初始化:使用 pthread_mutex_init() 函数动态地初始化互斥锁,这种方式可以在需要的时候进行销毁。
pthread_mutex_t mutex; // 动态初始化
pthread_mutex_init(&mutex, NULL); // 动态初始化互斥锁

如果需要设置互斥锁的属性,可以创建一个 pthread_mutexattr_t 对象,设置属性,然后将其传递给 pthread_mutex_init() 函数的第二个参数。

(2) 在需要保护的临界区域加锁:

pthread_mutex_lock(&mutex);
// 访问共享资源的代码

(3)在使用完共享资源后解锁:

pthread_mutex_unlock(&mutex);

四、线程销毁

pthread_join(tid, NULL);

在 POSIX 线程(pthreads)编程中,销毁线程实际上是由操作系统自动完成的,当线程的运行终止时,它会被系统自动清理。

  1. 线程函数返回:线程函数执行完毕后,会返回一个值(通过 pthread_exit 或从线程函数返回),这会导致线程的终止。任何线程都能调用 pthread_exit 来结束自己的执行。

  2. 主线程等待子线程结束:使用 pthread_join 函数,主线程可以阻塞等待特定子线程结束。如果子线程已经结束,它的资源被释放,此时 pthread_join 返回。如果子线程还没有结束,主线程会被放入睡眠状态,直到子线程结束为止。

  3. 分离状态(Detach):如果不想使用 pthread_join 来等待子线程结束,你可以调用 pthread_detach 函数将线程置于分离状态。一旦线程处于分离状态,它将在终止时自动释放其资源,无需主线程显式等待。

  4. 取消线程:可以使用 pthread_cancel 函数来请求取消另一个线程的执行。被取消的线程可以选择清理并自行终止,或者立即终止,具体行为取决于该线程对取消状态的处理策略。

  5. 线程清理处理:当线程被取消或正常结束时,可以设置清理处理函数,这些函数会在线程退出前被调用,以执行必要的清理工作。可以使用 pthread_cleanup_push 注册这样的清理函数,并用 pthread_cleanup_pop 来配对它们。

  6. 线程资源的释放:线程结束时,它所占用的所有用户级资源应该已经被释放,例如动态分配的内存等。但是,线程使用的系统资源(如文件描述符、互斥锁等)通常由操作系统在线程结束后自动释放。

  7. 避免僵尸线程:在多线程程序中,确保所有线程都已经结束才让主线程退出是很重要的。否则,未被加入(joined)或分离(detached)的线程可能会变成所谓的“僵尸线程”,它们的进程状态不会释放,直到父进程结束。

  8. 错误检查:对于线程相关的函数调用(如 pthread_create, pthread_join, pthread_detach 等),应始终检查它们的返回值以确保没有发生错误。

五、示例

注意编译时指定链接库 -lpthread

5.1 完整示例

2个线程分别打印当前时间:线程创建后即运行,所以创建时间不同。

#include <stdio.h>
#include <unistd.h>
#include<pthread.h>
#include <sys/time.h>
#include<time.h>void *print_time(void *arg){struct timeval current_time;if(gettimeofday(&current_time, NULL)==0){char *p = ctime(&current_time.tv_sec);printf("Current time is %s.\n",p);}else{return (void *)1;}return (void *)0;
}int main(){pthread_t tid1,tid2;int ret1,ret2;ret1=pthread_create(&tid1, NULL,print_time,(void *)1);sleep(2);ret2=pthread_create(&tid2, NULL,print_time,(void *)2);if(ret1||ret2){printf("Creat threads ailed.\n");return 1;}pthread_join(tid1,NULL);pthread_join(tid2,NULL);return 0;
}

在这里插入图片描述

5.2 信号量示例

现在修改一下,线程只有获得信号量的时候才能打印时间。

  • sem_init(&semaphore, 0, 1);:初始化信号量为 1,表示初始时可以访问临界区。
  • sem_wait(&semaphore);:在访问临界区之前等待信号量,如果为 0 则阻塞,直到变为大于 0 才继续执行。
  • sem_post(&semaphore);:在临界区访问结束后增加信号量,唤醒其他等待的线程。

信号量:

  • 信号量的作用
    -信号量是一种计数器,用于控制多个线程对共享资源的访问。
    • 当一个线程想要访问共享资源时,首先要等待信号量。
    • 如果信号量的值大于 0,表示资源空闲,线程可以继续执行,并将信号量减 1。
    • 如果信号量的值为 0,表示资源已被占用,线程会被阻塞,直到信号量的值变为大于 0。
  • 初始化:int sem_init(sem_t *restrict sem, int pshared, unsigned int value);
    • sem: 指向要初始化的信号量的指针。
    • pshared: 如果是0,则信号量是进程内共享的;如果是非0值,则用于进程间共享(但很少使用,通常不推荐,因为这涉及到进程间共享内存的复杂性)。
    • value: 信号量的初始值。
  • P、V 操作:
    • P操作 (sem_wait 或 sem_trywait): 减少信号量的值。如果信号量的值在操作之前是正的,它就简单地减一。如果信号量的值在操作之前是零,线程将被阻塞,直到信号量的值变成正数,然后它才减一。
    • V操作 (sem_post): 增加信号量的值。这通常用来表示一个线程已经释放了它所持有的资源。
  • 信号量分类:
    • 二值信号量:通常用于实现互斥(Mutual Exclusion),确保在任何时刻只有一个线程或进程可以访问关键部分代码或资源。它只有两个值,通常是0(表示资源不可用)和1(表示资源可用)。当一个线程尝试获取值为0的信号量时,它将被阻塞直到信号量的值变为1。
    • 计数信号量:是更一般化的同步机制,允许一定数量的线程同时访问某个资源。它的值可以是任何非负整数,代表可用资源的数量。当一个线程想要访问资源时,它会执行P操作,使信号量减一;当线程释放资源时,它会执行V操作,使信号量加一。如果信号量的值小于或等于0,则到达的线程将被阻塞。
      在这里插入图片描述
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <time.h>sem_t semaphore;void* printTime(void* arg) {sem_wait(&semaphore);time_t now;struct tm* timeinfo;time(&now);timeinfo = localtime(&now);printf("Thread ID: %ld, Current Time: %s", pthread_self(), asctime(timeinfo));sleep(2);  sem_post(&semaphore);return NULL;
}int main() {pthread_t tid1, tid2;sem_init(&semaphore, 0, 1); // 初始化信号量为 1pthread_create(&tid1, NULL, printTime, NULL);pthread_create(&tid2, NULL, printTime, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);sem_destroy(&semaphore);return 0;
}

在这里插入图片描述

把信号量初始值改为2,则2个线程可以同时打印时间:

在这里插入图片描述

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

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

相关文章

[实践经验]: visual studio code 实用技巧

目录 editor rulers 这里主要总结一些常用的VScode技巧&#xff0c;不定时更新… editor rulers 设置 -> 搜索 editor.rulers -> edit in settings.json "editor.rulers": [{"column": 80,"color": "#ff00FF"},]效果如图

Linux:设置别名命令alias

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 在Linux中alias命令用于为一串字符&#xff08;常代表命令&#xff09;设置一个别名&#xff0c;该别名在Bash读取并解析一行命令时会被展开。 下面是该命令的语法与选项…

python(django)之产品后台管理功能实现

1、添加新项目 在命令行输入以下代码 python manage.py startapp prroduct 2、添加路径和代码结构 在新项目目录下admin.py中加入以代码 from .models import Product class ProductAdmin(admin.ModelAdmin):list_display [product_name, product_desc,producter,created_…

牛客小白月赛86(D剪纸游戏)

题目链接:D-剪纸游戏_牛客小白月赛86 (nowcoder.com) 题目描述: 输入描述: 输入第一行包含两个空格分隔的整数分别代表 n 和 m。 接下来输入 n行&#xff0c;每行包含 m 个字符&#xff0c;代表残缺纸张。 保证&#xff1a; 1≤n,m≤10001 字符仅有 . 和 * 两种字符&#xf…

利用autodl服务器跑模型

1. 租用服务器 本地改模型 服务器 将改进好的、数据集处理好的模型压缩为zip文件上传到阿里云盘打开服务器AUTODL服务器&#xff0c;在主页中选择容器实例 在此位置进行开关机操作&#xff0c;若停止服务器&#xff0c;必须关机&#xff0c;不然会一直扣钱 2. 运行模型 选择…

Nacos详解,从安装到服务部署,及nginx反向代理

Nacos 安装 Windows安装 下载 在Nacos的GitHub页面&#xff0c;提供有下载链接&#xff0c;可以下载编译好的Nacos服务端或者源代码&#xff1a; GitHub主页&#xff1a;https://github.com/alibaba/nacos GitHub的Release下载页&#xff1a;https://github.com/alibaba/nacos…

peft模型微调_IA3

IA3&#xff08;论文&#xff1a;Few-Shot Parameter-Efficient Fine-Tuning is Better and Cheaper than In-Context Learning&#xff09;&#xff0c;通过学习向量来对激活层加权进行缩放&#xff0c;从而获得更强的性能&#xff0c;同时仅引入相对少量的新参数&#xff0c;…

鸿蒙:@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

在实际应用开发中&#xff0c;应用会根据开发需要&#xff0c;封装自己的数据模型。对于多层嵌套的情况&#xff0c;比如二维数组&#xff0c;或者数组项class&#xff0c;或者class的属性是class&#xff0c;他们的第二层的属性变化是无法观察到的。这就引出了Observed/Object…

【文末附gpt升级4.0方案】FastGPT详解

FastGPT知识库结构讲解 FastGPT是一个基于GPT模型的知识库&#xff0c;它的结构可以分为以下几个部分&#xff1a; 1. 数据收集&#xff1a;FastGPT的知识库是通过从互联网上收集大量的文本数据来构建的。这些数据可以包括维基百科、新闻文章、论坛帖子等各种类型的文本。 2…

转置卷积(transposed-conv)

一、什么是转置卷积 1、转置卷积的背景 通常&#xff0c;对图像进行多次卷积运算后&#xff0c;特征图的尺寸会不断缩小。而对于某些特定任务 (如图像分割和图像生成等)&#xff0c;需将图像恢复到原尺寸再操作。这个将图像由小分辨率映射到大分辨率的尺寸恢复操作&#xff0c…

聚类算法( clustering algorithm):

在前两章&#xff0c;我们学的是&#xff1a;线性回归&#xff0c;逻辑回归&#xff0c;深度学习(神经网络)&#xff0c;决策树&#xff0c;随即森林算法。他们都是监督学习的例子。 在这一章里&#xff0c;我们将学习非监督学习的算法。 什么是聚类算法&#xff1a; 聚类算…

Excel 使用SQL统计表格数据

一. 需求 ⏹有如下Excel表格&#xff0c;现要求统计每个店铺的每种类别的商品总销量和最大销量 ⏹详细数据如下 店铺商品类别销量一山店苹果水果27729一山店梨水果76175一山店菠萝水果14699一山店香蕉水果61371一山店西兰花蔬菜72822一山店大白菜蔬菜65090一山店小白菜蔬菜13…

git的下载与安装

下载 首先&#xff0c;打开您的浏览器&#xff0c;并输入Git的官方网站地址 点击图标进行下载 下载页面会列出不同操作系统和平台的Git安装包。根据您的操作系统&#xff08;Windows、macOS、Linux等&#xff09;和位数&#xff08;32位或64位&#xff09;&#xff0c;选择适…

k8s系列之十五 Istio 部署Bookinfo 应用

Bookinfo 应用中的几个微服务是由不同的语言编写的。 这些服务对 Istio 并无依赖&#xff0c;但是构成了一个有代表性的服务网格的例子&#xff1a;它由多个服务、多个语言构成&#xff0c;并且 reviews 服务具有多个版本。 该应用由四个单独的微服务构成。 这个应用模仿在线书…

[Halcon学习笔记]标定常用的Halcon标定板规格及说明

1、介绍 大多数标定的要求都是以实心圆或方格来作为标志点&#xff0c;所以一般的标定板为棋盘格或矩阵圆点图&#xff0c;高精度的相机标定过程中&#xff0c;大多是以比较明确的特征点来作为参考&#xff0c;所以通过识别标定板的圆形&#xff0c;拟合出精确的中心位置&…

【面试题】HashMap为什么可以插入null而Hashtable就不可以(源码分析)

首先hashmap可以插入null值&#xff0c;但是hashtable和hashcurrentHashmap是不支持的&#xff1b;这是因为在 hashmap对插入key为null进行了特殊处理&#xff0c;当插入的值为null的时候会将哈希值设置为0 但是hashtable会直接抛出异常&#xff1a; 并且hashmap是线程不…

基于C/C++的easyx图形库教程

文章目录: 一&#xff1a;前言 二&#xff1a;窗口&#xff08;宽高 背景颜色 窗口标题 弹出对话框&#xff09; 三&#xff1a;图形绘制&#xff08;点 线 矩形 圆 椭圆&#xff09; 四&#xff1a;文字&#xff08;颜色 大小 背景 位置 打印 文字居中&#xff09; 五&a…

Jest:JavaScript的单元测试利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

IDEA创建Sping项目只能勾选17和21,没有Java8?

解决办法: 替换创建项目的源 我们只知道IDEA页面创建Spring项目&#xff0c;其实是访问spring initializr去创建项目。故我们可以通过阿里云国服去间接创建Spring项目。将https://start.spring.io/或者http://start.springboot.io/替换为 https://start.aliyun.com/

2024 IEEE GRSS Data Fusion Contest Track 2 竞赛总结

一、成绩 二、尝试方案过程 模型上&#xff1a;Swin-smallSwin-base: Val 阶段效果较好Swin-largeKnet-ResNeSt101-FCN: crop-size_512x512 TTA-x5.0-7.0 iter-10k Test 阶段效果较好Segformer-b4Segformer-b5: crop-size_640x640 TTA-x5.0-7.0 2、输入与预处理&#xff1a; 对…