UNIX环境高级编程——线程控制

news2025/1/12 13:18:41

12.1 引言

本章讲解控制线程行为方面的详细内容,介绍线程属性和同步原语属性。

12.2 线程限制

在这里插入图片描述

12.3 线程属性

线程属性对象用pthread_attr_t结构表示,可以用这个结构修改线程默认属性,并把这些属性与创建的线程联系起来。

#include <pthread.h>

int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • pthread_attr_init函数以系统默认线程属性初始化attr指向的结构;
  • pthread_attr_destroy函数反初始化attr指向的结构,如果pthread_attr_init的实现对属性对象的内存空间是动态分配的,pthread_attr_destroy就会释放该内存空间,同时以无效的值初始化属性对象;
  • 下图总结了POSIX.1定义的线程属性:
    在这里插入图片描述
  1. 分离状态属性:detachstate
#include <pthread.h>

int pthread_attr_getdetachstate(const pthread_attr_t *restrict attr,
								int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int *detachstate);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • pthread_attr_getdetachstate函数获取当前的detachstate线程属性;
  • pthread_attr_setdetachstate函数设置detachstate线程属性;
  • detachstate的两个合法值:
    • PTHREAD_CREATE_DETACHED:以分离状态启动线程,应用程序不可获取线程的终止状态;
    • PTHREAD_CREATE_JOINABLE:正常启动线程,应用程序可以获取线程的终止状态。
  1. 线程栈属性:stackaddrstacksize
#include <pthread.h>

int pthread_attr_getstack(const pthread_attr_t *restrict attr,
						  void **restrict stackaddr,
						  size_t *restrict stacksize);
int pthread_attr_setstack(pthread_attr_t *attr,
						  void *stackaddr, size_t stacksize);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • stackaddr线程属性被定义为栈的最低内存地址;
  • stacksize线程属性被定义为栈的最小长度。

应用程序也可以通过pthread_attr_getstacksizepthread_attr_setstacksize函数读取或设置线程属性stacksize

#include <pthread.h>

int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,
							  size_t *restrict stacksize);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • 设置stacksize属性时,选择的stacksize不能小于PTHREAD_STACK_MIN
  1. 线程栈末尾警戒缓冲区大小属性:guardsize
#include <pthread.h>

int pthread_attr_getguardsize(const pthread_attr_t *restrict attr,
							  size_t *restrict guardsize);
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • guardsize属性默认值由具体实现来定义,常用值是系统页大小;
  • 若把guardsize属性设置为0,则不会提供警戒缓冲区;
  • 如果修改了线程属性stackaddr,会使栈警戒缓冲区机制无效,等同于把guardsize设置为0

12.4 同步属性

12.4.1 互斥量属性

互斥量属性用pthread_mutexattr_t结构表示。

#include <pthread.h>

int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • pthread_mutexattr_init函数以默认互斥量属性初始化attr
  • pthread_mutexattr_destroy函数反初始化attr指向的结构。
  1. 进程共享属性:pshared
#include <pthread.h>

int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr,
								 int *restrict pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,
								 int pshared);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • pthread_mutexattr_getpshared函数获取当前的pshared属性;
  • pthread_mutexattr_setpshared函数设置pshared属性;
  • pshared的两个合法值:
    • PTHREAD_PROCESS_PRIVATE:默认行为,在同一进程中的多个线程可以访问同一个同步对象;
    • PTHREAD_PROCESS_SHARED:不同进程中的线程可以访问同一个同步对象。
  1. 健壮属性:robust
    互斥量健壮属性与在多个进程间共享的互斥量有关,这意味着,当持有互斥量的进程终止时,需要解决互斥量状态恢复的问题。
#include <pthread.h>

int pthread_mutexattr_getrobust(const pthread_mutexattr_t *restrict attr,
								int *restrict robust);
int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr,
								int robust);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • pthread_mutexattr_getrobust函数获取当前的robust属性;
  • pthread_mutexattr_setrobust函数设置robust属性;
  • robust的两个合法值:
    • PTHREAD_MUTEX_STALLED:默认行为,持有互斥量的进程终止时不需要采取特别的动作,在这种情况下,使用互斥量的行为是未定义的,等待该互斥量解锁的应用程序会被有效地“拖住”;
    • PTHREAD_MUTEX_ROBUST:这个值将导致线程调用pthread_mutex_lock获取锁,而该锁被另一个进程持有,但它终止时并没有对该锁进行解锁,此时线程会阻塞,从pthread_mutex_lock返回的值EOWNERDEAD而不是0。应用程序可以通过这个特殊的返回值获知,若有可能,不管它们保护的互斥量状态如何,都需要进行恢复。

如果应用状态无法恢复,在线程对互斥量解锁以后,该互斥量将处于永久不可用状态。为了避免这样的问题,线程可以调用pthread_mutex_consistent函数,指明与该互斥量相关的状态在互斥量解锁之前是一致的:

#include <pthread.h>

int pthread_mutex_consistent(pthread_mutex_t *mutex);
										// 返回值:若成功,返回0;否则,返回错误编号
  • 如果线程没有先调用pthread_mutex_consistent就对互斥量进行了解锁,那么其他试图获取该互斥量的阻塞线程就会得到错误码ENOTRECOVERABLE;如果发生这种情况,互斥量将不再可用;
  • 线程通过提前调用pthread_mutex_consistent,能让互斥量正常工作,这样它就可以持续被使用。
  1. 类型属性:type
    类型互斥量属性控制着互斥量的锁定特性,POSIX.1定义了4种类型:
  • PTHREAD_MUTEX_NORMAL:一种标准互斥量类型,不做任何特殊的错误检查或死锁检测;
  • PTHREAD_MUTEX_ERRORCHECK:此互斥量类型提供错误检查;
  • PTHREAD_MUTEX_RECURSIVE:此互斥量类型允许同一线程在互斥量解锁之前对该互斥量进行多次加锁。递归互斥量维护锁的计数,在解锁次数和加锁次数不相同的情况下,不会释放锁;
  • PTHREAD_MUTEX_DEFAULT:此互斥量类型可以提供默认特性和行为。操作系统在实现它的时候可以把这种类型自由地映射到其他互斥量类型中的一种。
#include <pthread.h>

int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr, int *restrict type);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • pthread_mutexattr_gettype函数获取当前的type属性;
  • pthread_mutexattr_settype函数设置type属性。

12.4.2 读写锁属性

读写锁属性用pthread_rwlockattr_t结构表示。

#include <pthread.h>

int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • pthread_rwlockattr_init函数以默认读写锁属性初始化attr
  • pthread_rwlockattr_destroy函数反初始化attr指向的结构。

读写锁支持的唯一属性是进程共享属性,它有一对函数用于读取和设置读写锁的进程共享属性:

#include <pthread.h>

int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *restrict attr,
								  int *restrict pshared);
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr,
								  int pshared);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号

12.4.3 条件变量属性

条件变量属性用pthread_condattr_t结构表示。

#include <pthread.h>

int pthread_condattr_init(pthread_condattr_t *attr);
int pthread_condattr_destroy(pthread_condattr_t *attr);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • pthread_condattr_init函数以默认条件变量属性初始化attr
  • pthread_condattr_destroy函数反初始化attr指向的结构。
  1. 进程共享属性:pshared
    进程共享属性控制着条件变量是可以被单进程的多个线程使用,还是可以被多进程的线程使用。
#include <pthread.h>

int pthread_condattr_getpshared(const pthread_condattr_t *restrict attr,
								int *restrict pshared);
int pthread_condattr_setpshared(pthread_condattr_t *attr,
								int pshared);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • pthread_condattr_getpshared函数获取当前的pshared属性;
  • pthread_condattr_setpshared函数设置pshared属性。
  1. 时钟属性:clock_id
    时钟属性控制pthread_cond_timedwait函数的超时参数(tsptr)时采用的是哪个时钟,其合法值取自下图:
    在这里插入图片描述
#include <pthread.h>

int pthread_condattr_getclock(const pthread_condattr_t *restrict attr,
							  clockid_t *restrict clock_id);
int pthread_condattr_setclock(pthread_condattr_t *attr,
							  clockid_t clock_id);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • pthread_condattr_getclock函数获取时钟ID;
  • pthread_condattr_setclock函数修改时钟ID。

12.4.4 屏障属性

屏障属性用pthread_barrierattr_t结构表示。

#include <pthread.h>

int pthread_barrierattr_init(pthread_barrierattr_t *attr);
int pthread_barrierattr_destroy(pthread_barrierattr_t *attr);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • pthread_barrierattr_init函数对屏障属性对象进行初始化;
  • pthread_barrierattr_destroy函数对屏障属性对象进行反初始化。

目前定义的屏障属性只有进程共享属性,它控制着屏障是可以被多进程的线程使用,还是只能被初始化屏障的进程内的多线程使用,它有一对函数用于读取和设置进程共享属性:

#include <pthread.h>

int pthread_barrierattr_getpshared(const pthread_barrierattr_t *restrict attr,
								   int *restrict pshared);
int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr,
								   int pshared);
										// 两个函数的返回值:若成功,返回0;否则,返回错误编号
  • 进程共享属性的值可以是:
    • PTHREAD_PROCESS_SHARED:多进程中的多个线程可用;
    • PTHREAD_PROCESS_PRIVATE:只有初始化屏障的那个进程内的多个线程可用。

12.5 重入

  • 如果一个函数在相同的时间点可以被多个线程安全地调用,就称该函数是线程安全的;
  • 如果一个函数对多个线程来说是可重入的,就说这个函数就是线程安全的;
  • 如果函数对异步信号处理程序的重入是安全的,那么就可以说函数是异步信号安全的。

POSIX.1提供了以线程安全的方式管理FILE对象的方法,可以使用flockfileftrylockfile获取给定FILE对象关联的锁,这个锁是递归的:

#include <stdio.h>

int ftrylockfile(FILE *fp);
										// 返回值:若成功,返回0;若不能获取锁,返回非0数值
void flockfile(FILE* fp);
void funlockfile(FILE* fp);

为了避免对每一个字符的读写操作进行获取锁和释放锁的动作,出现了不加锁版本的基于字符的标准I/O例程:

#include <stdio.h>

int getchar_unlocked(void);
int getc_unlocked(FILE* fp);
										// 两个函数的返回值:若成功,返回下一个字符;若遇到文件尾或者出错,返回EOF
int putchar_unlocked(int c);
int putc_unlocked(int c, FILE* fp);
										// 两个函数的返回值:若成功,返回c;若出错,返回EOF

12.6 线程特定数据

线程特定数据,也称为线程私有数据,是存储和查询某个特定线程相关数据的一种机制。管理线程特定数据的函数可以提高线程间的数据独立性,使得线程不太容易访问到其他线程的线程特定数据。

在分配线程特定数据之前,需要创建与该数据关联的键,这个键将用于获取对线程特定数据的访问, pthread_key_create函数创建一个键:

#include <pthread.h>

int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *));
										// 返回值:若成功,返回0;否则,返回错误编号
  • 创建的键存储在keyp指向的内存单元中,这个键可以被进程中的所有线程使用,但每个线程把这个键与不同的线程特定数据地址进行关联;创建新键时,每个线程的数据地址设为空值;
  • pthread_key_create可以为所创建的键关联一个可选择的析构函数,当这个线程退出时,如果数据地址已被置为非空值,那么析构函数就会被调用,它唯一的参数就是该数据地址。

可以调用pthread_key_delete来取消键与线程特定数据值之间的关联关系:

#include <pthread.h>

int pthread_key_delete(pthread_key_t key);
										// 返回值:若成功,返回0;否则,返回错误编号
  • 调用pthread_key_delete并不会激活与键关联的析构函数。

需要确保分配的键并不会由于在初始化阶段的竞争而发生变动,解决这种竞争的办法是使用pthread_once

#include <pthread.h>

pthread_once_t initflag = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *initflag, void (*initfn)(void));
										// 返回值:若成功,返回0;否则,返回错误编号
  • initflag必须是一个非本地变量(如全局变脸或静态变量),而且必须初始化为PTHREAD_ONCE_INIT
  • 如果每个线程都调用pthread_once,系统就能保证初始化例程initfn只被调用一次,即系统首次调用pthread_once时。

键一旦创建以后,就可以通过调用pthread_setspecific函数把键和线程特定数据关联起来,通过调用pthread_getspecific函数获得线程特定数据的地址:

#include <pthread.h>

void *pthread_getspecific(pthread_key_t key);
										// 返回值:线程特定数据值;若没有值与该键关联,返回NULL
int pthread_setspecific(pthread_key_t key, const void *value);
										// 返回值:若成功,返回0;否则,返回错误编号

12.7 取消选项

可取消状态可取消类型这两个属性不包含在pthread_attr_t结构中,它们影响着线程在响应pthread_cancel函数调用时所呈现的行为。

  1. 可取消状态:state
#include <pthread.h>

int pthread_setcancelstate(int state, int *oldstate);
										// 返回值:若成功,返回0;否则,返回错误编号
  • pthread_setcancelstate把当前的可取消状态设置为state,把原来的可取消状态存储在由oldstate指向的内存单元,这两步是一个原子操作;
  • pthread_cancel调用并不等待线程终止,在默认情况下,线程在取消请求发出以后还是继续运行,直到线程到达某个取消点;取消点是线程检查它是否被取消的一个位置,如果取消了,则按照请求行事;
  • 可取消状态属性的两个可取值:
    • PTHREAD_CANCEL_ENABLE:默认行为,可以取消;
    • PTHREAD_CANCEL_DISABLE:对pthread_cancel的调用并不会杀死线程,取消请求对这个线程来说还处于挂起状态,当取消状态再次变为PTHREAD_CANCEL_ENABLE时,线程将在下一个取消点上对所有挂起的取消请求进行处理。

可以调用pthread_testcancel函数在程序中添加自己的取消点:

#include <pthread.h>

void pthread_testcancel(void);
  • 调用pthread_testcancel时,如果有某个取消请求正处于挂起状态,而且取消状态没有设置为无效,那么线程就会被取消;
  • 如果取消被设置为无效,pthread_testcancel调用没有任何效果。
  1. 可取消类型:type
#include <pthread.h>

int pthread_setcanceltype(int type, int *oldtype);
										// 返回值:若成功,返回0;否则,返回错误编号
  • pthread_setcanceltype函数把取消类型设置为type,把原来的取消类型返回到oldtype指向的整型单元;
  • 可取消类型属性的两个可取值:
    • PTHREAD_CANCEL_DEFERRED:默认行为,推迟取消,调用pthread_cancel以后,在线程到达取消点之前,并不会出现真正的取消;
    • PTHREAD_CANCEL_ASYNCHRONOUS:异步取消,线程可在任意时间撤消,不是非得遇到取消点才能被取消。

12.8 线程和信号

每个线程都有自己的信号屏蔽字,但是信号的处理是进程中所有线程共享的。

sigprocmask的行为在多线程的进程中并没有定义,线程必须使用pthread_sigmask函数来阻止信号发送:

#include <signal.h>

int pthread_sigmask(int how, const sigset_t *restrict set,
					sigset_t *restrict oset);
										// 返回值:若成功,返回0;否则,返回错误编号
  • set参数包含线程用于修改信号屏蔽字的信号集;
  • how参数的可取值:
    • SIG_BLOCK:把信号集添加到线程信号屏蔽字中;
    • SIG_SETMASK:用信号集替换线程的信号屏蔽字;
    • SIG_UNBLOCK:从线程信号屏蔽字中移除信号集。
  • 如果oset参数不为空,线程之前的信号屏蔽字就存储在它指向的sigset_t结构中;
    • 可以通过把set参数设置为NULL,并把oset参数设置为sigset_t结构的地址,来获取当前的信号屏蔽字,这种情况中的how参数会被忽略。

线程可以通过调用sigwait等待一个或多个信号的出现:

#include <signal.h>

int sigwait(const sigset_t *restrict set, int *restrict signop);
										// 返回值:若成功,返回0;否则,返回错误编号
  • set参数指定了线程等待的信号集;
  • 返回时,signop指向的整数将包含所等待到的信号;
  • 如果信号集中的某个信号在sigwait调用的时候处于挂起状态,那么sigwait将无阻塞地返回,在返回之前,sigwait将从进程中移除那些处于挂起等待状态的信号;
  • 线程在调用sigwait之前,必须阻塞那些它正在等待的信号,sigwait函数会原子地取消信号集的阻塞状态。

要把信号发送给线程,可以调用pthread_kill

#include <signal.h>

int pthread_kill(pthread_t thread, int signo);
										// 返回值:若成功,返回0;否则,返回错误编号
  • 可以传一个0值的signo来检查线程是否存在;
  • 如果信号的默认处理动作是终止该线程,那么把信号传递给某个线程仍然会杀死整个进程。

12.9 线程和fork

  • 当线程调用fork时,就为子进程创建了整个进程地址空间的副本;
  • 子进程通过继承整个地址空间的副本,还从父进程那儿继承了每个互斥量、读写锁和条件变量的状态。如果父进程包含一个以上的线程,子进程在fork返回以后,如果紧接着不是马上调用exec的话,就需要清理锁状态;
  • 在子进程内部,只存在一个线程,它是由父进程中调用fork的线程的副本构成的;如果父进程中的线程占有锁,子进程将同样占有这些锁;

要清除锁状态,可以通过调用pthread_atfork函数建立fork处理程序

#include <pthread.h>

int pthread_atfork(void (*prepare)(void), void (*parent)(void),
				   void (*child)(void));
										// 返回值:若成功,返回0;否则,返回错误编号
  • prepare fork处理程序由父进程在fork创建子进程前调用,这个fork处理程序的任务是获取父进程定义的所有锁;
  • parent fork处理程序是在fork创建子进程以后、返回之前在父进程上下文中调用的,这个fork处理程序的任务是对prepare fork处理程序获取的所有锁进行解锁;
  • child fork处理程序在fork返回之前在子进程上下文中调用,这个fork处理程序的任务是对prepare fork处理程序获取的所有锁进行解锁;
  • 不会出现加锁一次解锁两次的情况,因为子进程地址空间在创建时就得到了父进程定义的所有锁的副本。

12.10 线程和I/O

preadpwrite函数原子性的定位并执行I/O。

12.11 实例代码

chapter12

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯C++二面,全程2小时追问基础!

今天给大家分享星球一位同学腾讯面经&#xff0c;主要摘取了部分一二面经&#xff0c;然后部分问题我做了补充说明~ 星球原文&#xff1a;https://t.zsxq.com/0eO4O13HV&#xff0c;已获授权 一面 1、C11有哪些新特性&#xff0c;有哪些新关键字 2、C中结构体占多少字节&…

51单片机——I2C-EEPROM实验,小白讲解,相互学习

I2C介绍 I2C&#xff08;Inter&#xff0d;Integrated Circuit&#xff09;总线是由 PHILIPS 公司开发的两线式 串行总线&#xff0c;用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的 一种总线标准。它是同步通信的一种特殊形式&#xff0c;具有接口线少&#x…

【逆向工程核心原理:SEH】

SEH SEH是Windows操作系统提供的异常处理机制&#xff0c;在程序源代码中使用__ try、 __except、__finally关键字来具体实现。主要用在反调试中。 注&#xff1a; SEH与C中的try. catch 异常处理具有不同结构。从时间上看&#xff0c;与C的try、catch异常处理相比&#xff0…

uni-app--》uView组件库:提升您的uni-app开发体验

&#x1f3cd;️作者简介&#xff1a;大家好&#xff0c;我是亦世凡华、渴望知识储备自己的一名在校大学生 &#x1f6f5;个人主页&#xff1a;亦世凡华、 &#x1f6fa;系列专栏&#xff1a;uni-app &#x1f6b2;座右铭&#xff1a;人生亦可燃烧&#xff0c;亦可腐败&#xf…

MMDet3d样本均衡

MMDet3d样本均衡 文章目录 MMDet3d样本均衡CBGSDataset训练时数据是200帧&#xff0c;后面处理时&#xff0c;dataloader中数据变成了460帧&#xff0c;怎么均衡的&#xff1f;思考抽帧数计算某个类别帧数为0 Reference欢迎关注公众号【三戒纪元】 CBGSDataset **CBGS &#x…

UE虚幻引擎,Unity3D,Blender区别和联系

1. 官网手册 UnityUEBlenderUnity 用户手册 (2019.4 LTS) - Unity 手册虚幻引擎5.2文档 | 虚幻引擎5.2文档 (unrealengine.com)Blender 3.5 Reference Manual — Blender Manual 2. Unity, UnrealEngine, Blender的区别 Blender 是一款免费的开源软件&#xff0c;是一个开源…

Godot引擎 4.0 文档 - 循序渐进教程 - 脚本语言

本文为Google Translate英译中结果&#xff0c;DrGraph在此基础上加了一些校正。英文原版页面&#xff1a; Scripting languages — Godot Engine (stable) documentation in English 脚本语言 本课将概述 Godot 中可用的脚本语言。您将了解每个选项的优缺点。在下一部分中&…

CentOS7搭建伪分布式Hadoop(全过程2023)

##具体操作目录## 1.配置静态ip2.关闭防火墙3.修改主机名为 *master* &#xff0c;并重启虚拟机vi /etc/hostname 4.修改主机名与ip映射5.设置SSH免密登录6.安装配置java环境----------------------正式Hadoop配置1.移动安装包到合适位置2.解压安装包并重命名3.配置环境变量4.修…

know it and do it

overview&#xff1a; 在一盘盘有立即反馈的系统中&#xff0c;可以更直观的看到知道一个道理和能自然的用出来之间的鸿沟有多大。 这个就是日积月累的训练的意义了。 一夜回到解放前 继续金铲铲的游玩回味&#xff0c;之前一段时间忙于工作就放下了&#xff0c;后来新的版本…

20230521 AI 一周大事件汇总

&#x1f680; ChatGPT 上线联网和插件功能 OpenAI宣布将在这周推出联网和插件功能&#xff0c;位于Alpha和Beta通道的ChatGPT Plus用户都可使用70多个上线的插件。 更新意味着ChatGPT将利用最新的信息和资讯为使用者提供服务。 上线的ChatGPT插件种类涵盖了行程安排助理、代…

拿捏大厂面试官的高质量自动化测试工程师简历--看完必有所获

一、前言&#xff1a;简历&#xff08;职场敲门砖&#xff09; 作为软件测试的垂直领域深耕者&#xff0c;面试或者被面试都是常有的事&#xff0c;可是不管是啥&#xff0c;总和简历有着理不清的关系&#xff0c;面试官要通过简历了解面试者的基本信息、过往经历等&#xff0c…

阿里p10手敲python +pytest +yaml + Allure 实现接口自动化框架

以前弄过好多接口自动化框架的东西&#xff0c;比如httprunner2.0版本实现的接口自动化框架&#xff0c;还有httprunner3.X实现的接口自动化框架&#xff0c;这些都是开源的&#xff0c;实现起来比较简单。 以及使用pythonunittestddtyaml等工具实现的接口自动化框架等。 今天…

【腾讯云 Finops Crane 集训营】安装使用及EHPA弹性演示

随着时间的推移&#xff0c;降本增效成为了企业界和组织中的一个新口号。在2023年&#xff0c;这个口号进一步获得了广泛的认可和重要性&#xff0c;成为了许多组织在业务运营中的关键目标。在2023年&#xff0c;许多组织开始将降本增效作为战略性目标&#xff0c;并将其融入到…

3.fabric二进制工具包介绍

(1)Fabric二进制工具包: Fabric二进制工具包:Fabric二进制工具包(Fabric Binary Distribution)是Hyperledger Fabric的核心组件,它包含了一系列可执行的二进制文件,用于搭建、管理和操作Fabric网络。该工具包提供了一套命令行工具,可以执行各种与Fabric网络相关的任务…

模板(初阶)

目录 一、泛型编程二、函数模板2.1 函数模板的概念2.2 函数模板的格式2.3 函数模板的原理2.4 函数模板的实例化2.5 模板参数的匹配原则 三、类模板3.1 类模板的定义格式3.2 类模板的实例化 一、泛型编程 如何实现一个通用的Swap函数 void Swap(int& x, int& y) {int …

chatgpt赋能Python-pythonapp自动化

Python App自动化&#xff1a;优化SEO的终极解决方案 随着互联网的发展&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;变得日益重要。对于任何网站或应用程序开发人员来说&#xff0c;SEO应该是一个非常重要的考虑因素。为了帮助开发人员和企业提高其在线可见性&#x…

Squid代理服务器应用

在web架构中&#xff0c;用户一般进入负载均衡层&#xff0c;通过调度来访问web应用层&#xff0c;但是如果访问量太大&#xff0c;并发量较高&#xff0c;web应用层会吃不消&#xff0c;我们把静态资源、经常要访问的资源放入缓存&#xff0c;用户直接访问缓存层&#xff0c;加…

解析使用FPGA逻辑实现FIR滤波器的几种架构

有限脉冲响应(finite impulse response&#xff0c;FIR)数字滤波器 一、FIR数字滤波器理论介绍 FIR滤波器的实质就是输入序列与系统脉冲响应的卷积&#xff0c;即&#xff1a; 其中&#xff0c;N为滤波器的阶数&#xff0c;也即抽头数&#xff1b;x(n)为第n个输入序列&#xff…

人工智能轨道交通行业周刊-第45期(2023.5.15-5.21)

本期关键词&#xff1a;动车洗澡、热备列车、火车司机室、无缝线路、图像分割、自动标注 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro轨道…

Linux开发工具:yum和vim的使用

目录 一. Linux下的软件 1.1 软件安装的三种方法 1.2 采用yum安装软件 1.3 yum源的问题 二. vim开发工具的使用 2.1 vim的三种基本模式 2.2 命令模式下vim的常用指令 2.2.1 定位相关指令 2.2.2 光标移动相关指令 2.2.3 插入相关指令 2.2.4 复制粘贴相关指令 2.2.5 替…