当前位置: 首页 > news >正文

C++异步编程

thread

std::thread 类代表一个单独的执行线程。在创建与线程对象相关联时,线程会立即开始执行(在等待操作系统调度的延迟之后),从构造函数参数中提供的顶层函数开始执行。顶层函数的返回值被忽略,如果它通过抛出异常终止,则会调用 std::terminate

std::thread 对象也可以处于不表示任何线程的状态(默认构造、移动、分离或加入之后),而且执行线程可能不与任何 std::thread 对象关联(分离之后)。

std::thread 不可复制构造或复制赋值,但是可以移动构造和移动赋值。

构造函数:

  1. 默认构造函数。创建一个不表示任何线程的新的std::thread对象。
  2. 移动构造函数。将 other 所表示的线程转移给新的 std::thread 对象。在此调用后,other 不再表示一个线程。
  3. 创建一个新的 std::thread 对象并将其与一个线程关联起来,且新的线程开始执行。

析构函数:

销毁线程对象。 如果 *this 有关联的线程 (joinable() == true),则调用 std::terminate()。

移动构造函数:

如果 *this 仍然关联着一个正在运行的线程(即 joinable() == true),则调用 std::terminate() 终止程序。否则,将 other 的状态赋值给 *this,并将 other 设为默认构造状态。

Observers:

joinable:

joinable() 函数用于检查 std::thread 对象是否标识着一个活动的执行线程。一个默认构造的线程是不可结合(joinable)的。

get_id:

返回 std::thread::id 的值。

native_handle:

返回实现定义的底层线程句柄。对于LInux系统来说,就是返回一个Linux系统中定义的线程类型值。

hardware_concurrency(static):

返回实现支持的并发线程数。该值应仅被视为提示。

Operations:

join:

阻塞当前线程,直到由 *this 标识的线程执行完成。

detach:

将执行线程与线程对象分开,允许独立继续执行。调用 detach *this 后不再拥有任何线程。

swap:

交换两个线程对象的底层句柄

Non-member functions:

std::swap:

重载了次类的std::swap算法,其实现相当于调用成员函数swap。

管理线程的非成员函数:

std::this_thread::yield();

重新调度线程的执行,让其他线程运行。

std::this_thread:get_id();

返回当前线程的id。

std::this_thread::sleep_for();

阻塞当前线程的执行,至少持续指定的 sleep_duration。

由于调度或资源争用延迟的原因,此函数可能会阻塞的时间超过 sleep_duration。

std::sleep_until();

阻塞当前线程的执行,直到达到指定的 sleep_time。

std::mutex

互斥锁, 一种独占性资源,因此没有复制构造函数和复制运算符。线程通过调用它的成员函数lock或try_lock才能拥有该互斥量。如果一个互斥量在任何线程仍然拥有它的情况下被销毁,或者一个线程在拥有互斥量时终止,程序的行为是未定义的。

Member types:

构造函数:

只有默认构造函数。复制构造函数被删除。也没有移动构造函数。

Locking

lock:

对互斥量加锁。

try_lock:

尝试锁定互斥锁。立即返回,成功锁定后返回true,否则返回false。

unlock:

对互斥锁解决。

Native handle:

native_handle();

返回底层实现定义的本地句柄对象。

std::timed_mutex

timed_mutex 提供了mutex的全部功能,除此之外,还提供了超时的情况下锁的是否锁定的问题。在Linux系统中,它和std::mutex的native_handle()的返回值是一样的。

它提供了std::mutex的全部的成员函数。以下是std::mutex没有的两个成员函数。

Locking:

try_lock_for:

尝试锁定互斥。阻塞直到指定的持续时间 timeout_duration 已过(超时)或锁被获取(拥有互斥),以先到者为准。成功获取锁后返回 true,否则返回 false。

try_lock_until:

尝试锁定互斥量。阻塞直到达到指定的超时时间(timeout_time)或成功获取锁定(拥有互斥量),以先到者为准。成功获取锁定时返回 true,否则返回 false。

如果超时时间已经过去,此函数的行为类似于 try_lock()。

std::shared_mutex

shared_mutex 具有两个级别的访问权限:

  • 共享访问:多个线程可以共享对同一个互斥量的拥有权。
  • 独占访问:只有一个线程可以拥有互斥量。

在同一个线程内,同一时间只能获取一个锁(共享锁或独占锁)。它不能被拷贝。

构造函数:

默认构造函数;没有拷贝构造函数和移动构造函数。

没有赋值运算符。

Exclusive locking

lock:

获得对 shared_mutex 的独占所有权。如果另一个线程在同一个 shared_mutex 上持有独占锁或共享锁,调用锁定将阻塞执行,直到所有此类锁都被释放。当 shared_mutex 以独占模式锁定时,不能同时持有其他任何类型的锁。

try_lock:

尝试锁定互斥。立即返回。成功锁定后返回 true,否则返回 false。即使当前互斥项未被任何其他线程锁定,该函数也允许假失败并返回 false。如果 try_lock 被一个已经在任何模式(共享或独占)下拥有该互斥项的线程调用,其行为将是未定义的。

unlock:

对此锁解锁。

shared locking:

lock_shared:

获取互斥项的共享所有权。

try_lock_shared:

尝试在共享模式下锁定互斥。立即返回。成功锁定后返回 true,否则返回 false。即使互斥当前未被任何其他线程独占锁定,该函数也允许错误地失败并返回 false。

unlock_shared:

从调用线程的共享所有权中释放互斥。在共享模式下,mutex 必须被当前执行线程锁定,否则其行为将是未定义的。

std::shared_timed_mutex

和std::shared_mutex相似,相比于它,没有native_handle()这样获取底层资源的函数,且多了这四个参数:

try_lock_for:

尝试获取互斥量的锁。阻塞直到指定的持续时间 timeout_duration 经过(超时)或者成功获取锁(拥有互斥量),以先到者为准。如果成功获取锁,则返回 true,否则返回 false。由于调度或资源争用延迟,此函数可能会阻塞超过 timeout_duration 的时间。与 try_lock() 类似,即使在 timeout_duration 的某个时间点上互斥量没有被其他线程锁定,此函数也可以出现虚假失败并返回 false。

try_lock_until:

尝试获取互斥量的锁。阻塞直到达到指定的超时时间 timeout_time(到达超时)或成功获取锁(拥有互斥量),以先到者为准。如果成功获取锁,则返回 true,否则返回 false。如果超时时间 timeout_time 已经过去,则此函数的行为类似于 try_lock()。与 try_lock() 类似,即使在超时时间之前互斥量没有被其他线程锁定,该函数也可以出现虚假失败并返回 false。

try_lock_shared_for:

与try_lock_for类似,只是获取的是共享锁。

try_lock_shared_until:

与try_lock_until类似,只是获取的是共享锁。

锁管理

std::lock_guard

lock_guard 类是一个互斥包装器, 当创建 lock_guard 对象时,它会尝试获取所给互斥的所有权。当控制权离开创建 lock_guard 对象的作用域时,lock_guard 会被析构,mutex 也会被释放。lock_guard类不可被拷贝,没有赋值运算符。

它的模板参数必须符合BasicLockable要求。

构造函数:

  1. 接受一个锁参数,然后立刻调用其lock()成员函数。
  2. 获取 mutex m 的所有权,但不试图锁定它。如果当前线程未持有 m 上的非共享锁,则该行为未定义。

析构函数:

调用拥有的锁的unlock()。

std::unique_lock

unique_lock是一个通用的互斥量所有权包装器,允许延迟锁定、限时尝试锁定、递归锁定、锁的所有权转移以及与条件变量一起使用。类unique_lock是可移动的,但不可复制。

构造函数:

  1. 默认构造函数,构造一个没有关联互斥量的对象。
  2. 移动构造函数,用其他对象的内容初始化unique_lock对象,同时将其他对象置为没有关联互斥量。
  3. 使用互斥量m构造一个关联的unique_lock对象,然后可以通过选择是否传参以及传递什么参数,使互斥量被锁定、不锁定、调用try_lock()锁定、认为互斥量是非共享锁定状态的、调用try_lock_for或调用try_lock_until的。

析构函数:

如果 *this 有关联的互锁体,并且已获得其所有权,则互锁体被解锁。

移动赋值操作符:

使用移动语义将内容替换为其他内容。如果在调用 *this 之前已关联了一个互斥项并获得了它的所有权,则互斥项将被解锁。

Locking:

lock:

锁定拥有的互斥。实际上是调用拥有互斥的lock成员函数。

try_lock:

尝试在不阻塞的情况下锁定(即获取)相关的互斥。实际上是调用 mutex()->try_lock()。

try_lock_for:

实际上调用了 mutex()->try_lock_for(timeout_duration)。

try_lock_until:

实际上调用了 mutex()->try_lock_until(timeout_time)。

unlock:

解锁。实际上调用了mutex()->unlock();

Modifiers:

swap;

交换锁对象的内部状态。

release():

中断相关互斥(如果有)与 *this 的关联。不会解锁任何锁。

Observers:

mutex();

返回指向相关静态代理的指针,如果没有相关静态代理,则返回空指针。

owns_lock();

检查 *this 是否拥有锁定的互斥。

std::shared_lock

shared_lock是一个通用的共享互斥量所有权包装器,允许延迟锁定、定时锁定和锁的所有权转移。通过对shared_lock进行锁定,将以共享模式锁定关联的共享互斥量. shared_lock类是可移动的,但不可复制。

构造函数:

  1. 默认构造函数,构造一个没有关联互斥量的对象。
  2. 移动构造函数,用其他对象的内容初始化shared_lock对象,同时将其他对象置为没有关联互斥量。
  3. 使用互斥量m构造一个关联的shared_lock对象,然后可以通过选择是否传参以及传递什么参数,使互斥量以共享模式被锁定、不锁定、调用try_lock_shared()锁定、认为互斥量是共享锁定状态的、调用try_lock_shared_for或调用try_lock_shared_until的。

析构函数:

如果 *this 有关联的互锁体,并且已获得其所有权,则通过调用 unlock_shared() 来解锁互锁体。

赋值运算符:

使用移动语义将内容替换为其他内容。如果在调用 *this 之前已关联了一个互斥项并获得了它的所有权,则会通过调用 unlock_shared() 来解锁互斥体。

Locking:

lock:

以共享模式锁定相关的互斥。实际上是调用拥有互斥的lock_shared成员函数。

try_lock:

尝试在不阻塞的情况下以共享模式锁定相关的互斥。实际上是调用 mutex()->try_lock_shared()。

try_lock_for:

实际上调用了 mutex()->try_lock_shared_for(timeout_duration)。

try_lock_until:

实际上调用了 mutex()->try_lock_shared_until(timeout_time)。

unlock:

解锁。实际上调用了mutex()->unlock_shared();

Modifiers:

swap;

交换锁对象的内部状态。

release():

中断相关互斥(如果有)与 *this 的关联。不会解锁任何锁。

Observers:

mutex();

返回指向相关静态代理的指针,如果没有相关静态代理,则返回空指针。

owns_lock();

检查 *this 是否拥有共享互斥量的共享所有权。

std::scoped_lock

scoped_lock是一个互斥量包装器, 用于在作用域块的持续时间内拥有零个或多个互斥量。如果给定了多个互斥量,则会使用避免死锁的算法,类似于std::lock的行为。scoped_lock类是不可复制的。

构造函数:

  1. 获取给定互斥量的所有权,即调用对应的lock成员函数。
  2. 在不尝试锁定任何互斥量的情况下获取互斥量 m... 的所有权。除非当前线程对 m... 中的每个对象都持有非共享锁,否则行为是未定义的。

析构函数:

释放所有互斥的所有权,及调用每个互斥体的unlock()成员函数。

赋值运算符已经被删除。

Call once

call_once:

once_flag:

Condition variables

条件变量的唤醒丢失与虚假唤醒问题。

std::condition_variable

condition_variable 类是与 std::mutex 一起使用的同步原语,用于阻塞一个或多个线程,直到另一个线程修改了共享变量(条件)并通知 condition_variable。std::condition_variable仅适用于std::unique_lockstd::mutex,这样可以在某些平台上实现最高效率。

它不可被移动或复制。

构造函数:

默认构造函数,构造一个std::condition_variable对象。

析构函数:

销毁 std::condition_variable 类型的对象。只有在所有线程都已被通知的情况下才能安全地调用析构函数。

Notification:

notify_one():

如果有线程正在等待 *this,调用 notify_one 会解除其中一个等待线程的阻塞。

notify_all():

解除当前等待 *this 的所有线程的阻塞。

Waiting:

wait:

wait 函数会导致当前线程阻塞,直到条件变量被通知或出现虚假唤醒。它有两个重载。

  1. 只有参数锁:原子性地解锁 lock,阻塞当前执行的线程,并将其添加到等待 *this 的线程列表中。它被唤醒而解除阻塞时,都会重新获取互斥锁并退出 wait 函数。
  2. 有参数锁和谓词:等价于如下代码:
while (!stop_waiting()) {  // stop_waiting函数是谓词wait(lock);
}

这个重载函数可以避免虚假唤醒的问题。

这里的锁必须是std::unique_lockstd::mutex

wait_for: wait_until:

前者是最多阻塞的相对超时时间,后者是最多阻塞到某个时间点。它们其余部分和wait一致。

Native handle:

native_handle():访问 *this 的本地句柄。

std::condition_variable_any

class condition_variable_any 是 std::condition_variable 的一个更通用的版本。而 std::condition_variable 只能与 std::unique_lockstd::mutex 一起使用,condition_variable_any 可以操作任何满足 BasicLockable 要求的锁。

class std::condition_variable_any 是一个 StandardLayoutType。它不可被移动或复制。

如果锁是 std::unique_lockstd::mutex,则 std::condition_variable 可能提供更好的性能。

下面列出些std::condition_variable没有的功能:

wait;wait_for; wait_until:

都多了第三个重载,多了一个stoken变量:多了一个 std::stop_token 对象,用于支持取消等待操作。当外部发出取消请求时,可以通过该对象检查并中止等待。

Latches and Barriers

Futures

Futures 功能是并发编程机制,旨在简化多线程编程和异步操作的处理。Futures 提供了一种在一个线程中计算值或执行任务,并在另一个线程中获取结果的方法。

它的核心组件时std::futurestd::promisestd::future 对象与 std::promise 对象之间共享一个状态。通过 std::promise 对象设置的值可以通过与其关联的 std::future 对象来获取。这样就可以使一个线程使用 std::promise 对象来设置异步操作的结果,而另一个线程使用对应的 std::future 对象来获取结果。

std::futuer

std::future提供了一种访问异步操作结果的机制, 通过std::async、std::packaged_task或std::promise创建的异步操作可以向该异步操作的创建者提供一个std::future对象。异步操作的创建者可以使用各种方法来查询、等待或从std::future中提取值。

构造函数:

  1. 默认构造函数,创建一个没有共享状态的 std::future 对象。
  2. 移动构造函数,构造后,被移动的对象没有共享状态
  3. 拷贝构造函数被删除。

析构函数:

释放任何共享状态不会阻塞等待共享状态变为就绪,除非以下所有条件都成立时可能会阻塞:(一定会阻塞吗?????)

  • 共享状态是通过调用 std::async 创建的。
  • 共享状态尚未就绪。
  • 当前对象是对共享状态的最后一个引用。

这些操作只有在任务的启动策略为 std::launch::async 时才会阻塞

只有移动赋值运算符,没有拷贝赋值运算符。移动后,被移动的对象没有共享状态。

share():

将 *this 的共享状态(如果有的话)转移给一个 std::shared_future 对象。在调用 share 后,valid() == false

Getting the result:

get():

阻塞当前线程,直到future准备妥当并返回该值,或者抛出异步运行的函数的异常或被设置的异常. 在调用此成员函数后,共享状态会被释放, valid() 为 false。如果在调用此函数之前 valid() 为 false,则行为是未定义的。

State:

valid:

检查 future 是否引用共享状态。

wait:

阻塞直到结果变为可用。

wait_for:

等待结果变为可用。阻塞直到指定的 timeout_duration 经过或结果可用,以先到者为准。返回值标识结果的状态。如果 future 是通过使用lazy evaluation的方式调用 std::async 的结果,该函数会立即返回而不等待。

wait_until:

wait_until 函数等待结果变为可用。它会阻塞直到达到指定的 timeout_time 或结果可用,以先到者为准。返回值指示 wait_until 返回的原因。如果 future 是通过使用lazy evaluation的方式调用 std::async 的结果,该函数会立即返回而不等待。

std::shared_future

std::shared_future类似于 std::future,但允许多个线程等待相同的共享状态。std::shared_future 是既可移动,也可复制的,多个共享的 std::shared_future 对象可以引用相同的共享状态。通过各自的 std::shared_future 对象,多个线程可以安全地访问相同的共享状态。

构造函数:

  1. 默认构造函数。构造一个空的shared_future, 不引用共享状态。
  2. 拷贝构造函数,构造一个引用与other相同共享状态(如果有的话)的shared_future.
  3. 移动构造函数,将 other 持有的共享状态转移给 *this。构造后,other.valid() == false,且 this->valid() 的返回值与在构造之前 other.valid() 的返回值相同。

赋值运算符:

  1. 拷贝赋值运算符:1. 释放任何共享状态,并将 other 的内容赋值给 *this。赋值后,this->valid() == other.valid()
  2. 移动赋值运算符:1. 释放任何共享状态,并将 other 的内容移动赋值给 *this。赋值后,other.valid() == false,并且 this->valid() 的返回值与赋值之前的 other.valid() 的返回值相同。

Getting the result:

get:

get 成员函数会等待直到 shared_future 有一个有效的结果,并且(根据使用的模板)获取它。它实际上会调用 wait() 来等待结果。与 std::future 不同,当调用 get() 时,std::shared_future 的共享状态不会无效。

State:

valid();

检查 shared_future 是否引用共享状态。

wait():

调用后 valid() == true。如果在调用此函数之前 valid() == false,则行为未定义。

wait_for();

等待结果可用。阻塞直到指定的 timeout_duration 已过或结果可用,以先到者为准。返回值标识结果的状态。如果 future 是调用 std::async 并使用了懒评估的结果,则此函数无需等待,立即返回。

wait_until();

wait_until 等待结果可用。它会阻塞,直到达到指定的 timeout_time 或结果可用为止,以先到者为准。返回值说明 wait_until 返回的原因。如果 future 是调用 async 时使用了懒评估的结果,则此函数会立即返回而无需等待。

std::async()

函数模板 std::async 异步地运行函数 f(可能在一个独立的线程中,该线程可能是线程池的一部分),并返回一个 std::future,最终将保存该函数调用的结果。它可以根据系统情况自动选择是独立启动一个线程运行,还是在对应的future调用get时运行;也可以由调用者指定任务调用策略。

任务调用策略:

  1. std::launch::async; 开启一个独立线程执行任务
  2. std::launch::deferred; 使用延迟批评估。

请注意,除了调用 std::async 之外,通过其他方式获得的 std::futures 的析构函数永远不会阻塞。

构造函数:

  1. 不加策略的构造函数
  2. 加策略的构造函数

std::package_task<>

类模板 std::packaged_task 可以封装任何可调用目标,以便可以异步调用它。它的返回值或抛出的异常被存储在一个共享状态中,可以通过 std::future 对象访问该状态。它不可被复制。

默认构造函数:

  1. 构造一个没有任务和共享状态的 std::packaged_task 对象。
  2. 构造一个具有共享状态和任务副本的 std::packaged_task 对象,使用 std::forward<F>(f) 进行初始化。
  3. 复制构造函数被删除,std::packaged_task 是只可移动的
  4. 移动构造函数,构造一个具有共享状态和任务的 std::packaged_task,该状态和任务原先由 rhs 拥有,将 rhs 置于无共享状态和已移动的任务状态。

析构函数:

放弃共享状态并销毁存储的任务对象。如果共享状态在准备就绪之前被放弃,则会存储一个 std::future_error 异常,错误代码为 std::future_errc::broken_promise。

复制运算符:

只有移动赋值运算符。移动赋值运算符:释放共享状态(如果有),销毁之前持有的任务,并将共享状态和 rhs 拥有的任务移入 *this。

valid();

检查是否有一个共享状态,即是否包含一个有效的任务。

swap():

将"*this"和"other"的共享状态和存储的任务进行交换。

Getting the result:

get_future:

用于获取一个 std::future 对象,该对象与当前 std::packaged_task 共享相同的共享状态。get_future() 函数只能调用一次.

Execution:

operator():

执行存储中的任务。任务的返回值或抛出的任何异常都会存储在共享状态中。

make_ready_at_thread_exit:

共享状态只有在当前线程退出并且所有具有线程局部存储期的对象被销毁后,才会准备就绪。

reset():

重置状态,放弃之前的执行结果。构建新的共享状态。

std::promise<>

类模板 std::promise 提供了一种存储值或异常的机制,这些值或异常可以通过由 std::promise 对象创建的 std::future 对象在异步方式下获取。std::promise 对象只能使用一次,因此不可被复制。

每个 promise 关联一个共享状态, 它可以对共享状态执行三种操作:

  1. 准备就绪:
    promise 将结果或异常存储在共享状态中。标记状态为就绪,并解除任何等待与共享状态相关联的 future 的线程的阻塞。
  2. 释放:
    promise 放弃对共享状态的引用。如果这是最后一个对共享状态的引用,那么共享状态将被销毁。
  3. 放弃:
    promise 将类型为 std::future_error,错误代码为 std::future_errc::broken_promise 的异常存储在共享状态中,使共享状态变为就绪状态,然后释放它。

构造函数:(拷贝构造函数被删除)

  1. 默认构造函数。使用空的共享状态构造promise。
  2. 移动构造函数。使用移动语义构造 promise,使用其他 promise 的共享状态。构造完成后,其他 promise 不再具有共享状态。

析构函数:

  1. 如果共享状态已就绪,则释放共享状态。
  2. 如果共享状态未就绪,则存储一个 std::future_error 类型的异常对象(错误条件为 std::future_errc::broken_promise),使共享状态就绪并释放它。

赋值运算符:(没有拷贝运算符)

移动赋值操作符。首先,放弃共享状态,然后通过执行 std::promise(std::move(other)).swap(*this) 赋值给 other 的共享状态。

Getting the result:

get_future:

返回与 *this 相同共享状态相关联的std::future。

set_value; set_value_at_thread_exit;

原子式地将值存储到共享状态中,并使状态就绪。如果没有共享状态或共享状态已存储值或异常,则会抛出异常。

前者是立即让共享状态就绪,后者是等当前线程退出时,所有具有线程本地存储期限的变量都已销毁,状态才会就绪。

set_exception; set_exception_at_thread_exit;

除了存储的是异常,其余和set_value; set_value_at_thread_exit;完全一致。

set_value: 保存值

set_exception: 保存异常

相关文章:

C++异步编程

thread std::thread 类代表一个单独的执行线程。在创建与线程对象相关联时&#xff0c;线程会立即开始执行&#xff08;在等待操作系统调度的延迟之后&#xff09;&#xff0c;从构造函数参数中提供的顶层函数开始执行。顶层函数的返回值被忽略&#xff0c;如果它通过抛出异常…...

dfs专题(记忆化搜索)P1141 01迷宫——洛谷(题解)

题目描述 有一个仅由数字 00 与 11 组成的 &#xfffd;&#xfffd;nn 格迷宫。若你位于一格 00 上&#xff0c;那么你可以移动到相邻 44 格中的某一格 11 上&#xff0c;同样若你位于一格 11 上&#xff0c;那么你可以移动到相邻 44 格中的某一格 00 上。 你的任务是&#…...

pip 安装出现报错 SSLError(SSLError(“bad handshake

即使设置了清华源&#xff1a; pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simplepip 安装包不能配置清华源&#xff0c;出现报错: Retrying (Retry(total2, connectNone, readNone, redirectNone, statusNone)) after connection broken by ‘SSLE…...

新概念英语第二册(46)

【New words and expressions】生词和短语&#xff08;12&#xff09; unload v. 卸&#xff08;货&#xff09; wooden adj. 木制的 extremely adv. 非常&#xff0c;极其 occur …...

动态规划入门题目

动态规划&#xff08;记忆化搜索&#xff09;&#xff1a; 将给定问题划分成若干子问题&#xff0c;直到子问题可以被直接解决。然后把子问题的答保存下来以免重复计算&#xff0c;然后根据子问题反推出原问题解的方法 动态规划也称为递推&#xff08;暴力深搜记忆中间状态结果…...

探索云性能测试的各项功能有哪些?

云性能测试作为现代软件开发和部署过程中不可或缺的一环&#xff0c;为确保系统在各种条件下的高效运行提供了关键支持。本文将介绍云性能测试的各项功能&#xff0c;帮助您更好地了解其在软件开发生命周期中的重要性。 1. 负载测试 云性能测试的首要功能之一是负载测试。通过模…...

(大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量

今天&#xff0c;面试了一家公司&#xff0c;什么也不说先来三道面试题做做&#xff0c;第一题。 那么&#xff0c;我们就开始做题吧&#xff0c;谁叫我们是打工人呢。 题目是这样的&#xff1a; 统计除豪车外&#xff0c;销售最差的车 车辆按批销售&#xff0c;每次销售若干…...

Git安装,Git镜像,Git已安装但无法使用解决经验

git下载地址&#xff1a; Git - 下载 (git-scm.com) <-git官方资源 Git for Windows (github.com) <-github资源 CNPM Binaries Mirror (npmmirror.com) <-阿里镜像&#xff08;推荐&#xff0c;镜…...

Python与CAD系列高级篇(二十五)分类提取坐标到excel(补充圆半径、线长度、圆弧)

目录 0 简述1 分类提取坐标到excel2 结果展示0 简述 上一篇中介绍了:对点、直线、多段线、圆、样条曲线分类读取坐标并提取到excel。考虑到进一步提取图形信息,此篇补充对圆半径、线长度以及圆弧几何信息的提取。 1 分类提取坐标到excel 代码实现: import math import nump…...

Linux安装Influxdb

Linux安装Influxdb 1、安装步骤1.1、安装Influxdb步骤1.2、Influxdb默认安装路径1.3、命令行操作Influxdb&#xff0c;建库&#xff0c;建用户1.3.1 进入influxdb命令行1.3.2 创建用户1.3.2 库查询和创建 1、安装步骤 1.1、安装Influxdb步骤 yum install -y wget #下载安装包…...

Flutter CustomPainter 属性介绍与使用

Flutter 中的 CustomPainter 是一个强大的工具&#xff0c;允许开发者通过自定义绘制来创建各种复杂的图形和动画。本文将介绍 CustomPainter 的一些重要属性以及如何使用它们来实现自定义绘制。 1. CustomPainter 简介 CustomPainter 是一个抽象类&#xff0c;用于自定义绘制…...

基于Javaweb开发的二手图书零售系统详细设计【附源码】

基于Javaweb开发的二手图书零售系统详细设计【附源码】 &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制系统…...

【JaveWeb教程】(35)SpringBootWeb案例之《智能学习辅助系统》登录功能的详细实现步骤与代码示例(8)

目录 案例-登录和认证1. 登录功能1.1 需求1.2 接口文档1.3 思路分析1.4 功能开发1.5 测试 案例-登录和认证 在前面的课程中&#xff0c;我们已经实现了部门管理、员工管理的基本功能&#xff0c;但是大家会发现&#xff0c;我们并没有登录&#xff0c;就直接访问到了Tlias智能…...

6.1 内存模式概述

Bruce Powel Douglass大师介绍-CSDN博客 嵌入式软件开发从小工到专家-CSDN博客 C嵌入式编程设计模式源码-CSDN博客 “内存管理模式”介绍了几种内存管理的模式&#xff0c;每种模式都针对特定的系统需求和约束设计。 6.2 静态分配模式&#xff08;Static Allocation Patter…...

Python中容器类型的数据

目录 序列 序列的索引操作 加和乘操作 切片操作 成员测试 列表 创建列表 追加元素 插入元素 替换元素 删除元素 元组 创建元组 元组拆包 集合 创建集合 修改集合 字典 创建字典 修改字典 访问字典视图 遍历字典 若我们想将多个数据打包并且统一管理&…...

虚拟机安装Centos8.5

记得看目录哦&#xff01; 附件1. 新建虚拟机2. 安装Centos8.5 附件 安装包自行下载 https://mirrors.aliyun.com/centos/8/isos/x86_64/ 1. 新建虚拟机 2. 安装Centos8.5 启动虚拟机–选择第一个install Centos8.5 记得接收许可证...

ENVI下基于知识决策树提取地表覆盖信息

基于知识的决策树分类是基于遥感影像数据及其他空间数据,通过专家经验总结、简单的数学统计和归纳方法等,获得分类规则并进行遥感分类。分类规则易于理解,分类过程也符合人的认知过程,最大的特点是利用的多源数据。 决策树分类主要的工作是获取规则,本文介绍使用CART算法…...

arco design table遇到的一些问题

问题1&#xff1a;不知情就成了树形table table中不知道为啥就多了个树形加号在前面&#xff0c;查找问题后发现&#xff0c;是后端返回的数据中有children&#xff0c;框架中默认对这个参数做了树形结构。 解决办法&#xff1a; 当时没找到取消或者修改字段的属性或方法&…...

Linux系统——文本三剑客

目录 一、grep 1.格式 2.选项 2.1 grep重定向 2.2grep -m 匹配到几次停止 2.3grep -i 忽略大小写 2.4grep -n 显示行号 2.5grep -c 统计匹配行数 2.6grep -A 后几行 2.7grep -C 前后三行 2.8grep -B 前三行 2.9grep -e 或 2.10grep -w 匹配整个单词 2.11grep -r…...

代码随想录算法训练营Day38|动态规划理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

目录 动态规划理论基础 什么是动态规划 动态规划的解题步骤 动态规划的debug 509. 斐波那契数 前言 思路 算法实现 方法一&#xff1a;动态规划 方法二&#xff1a;递归法 70. 爬楼梯 前言 思路 算法实现 拓展 746. 使用最小花费爬楼梯 算法实现 总结 动态规划…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...