【探索Linux】—— 強大的命令行工具 P.21(多線程 | 線程同步 | 條件變量 | 線程安全)

在這里插入圖片描述

閱讀導航

  • 引言
  • 一、線程同步
    • 1. 競態條件的概念
    • 2. 線程同步的概念
  • 二、條件變量
    • 1. 條件變量函數
      • ?使用前提
      • (1)初始化條件變量
      • (2)等待條件滿足
      • (3)喚醒等待
        • pthread_cond_broadcast()
        • pthread_cond_signal()
      • (4)銷毀條件變量
    • 2. 條件變量使用規范
      • (1)條件變量的使用流程
      • (2)條件變量的使用注意事項
    • 3. 使用條件變量的示例
  • 三、線程安全
    • 1. 概念
    • 2. 常見的線程不安全的情況
    • 3. 常見的線程安全的情況
    • 4. 可重入與線程安全的關系(八股文)
      • (1)可重入與線程安全的聯系
      • (2)可重入與線程安全的區別
  • 溫馨提示

引言

在上一篇文章中,我們詳細探討了多線程編程的基礎概念,包括線程互斥、互斥鎖以及死鎖和資源饑餓等問題。我們了解到,在多線程環境下,為了防止數據競爭和保證程序的正確性,需要采用一定的同步機制來協調線程之間的執行順序。本篇文章將繼續深入探討多線程編程中的另一組關鍵概念:線程同步、條件變量和線程安全

在這篇文章中,我們將具體介紹線程同步的技術和模式,探討條件變量的工作原理以及如何在實際編程中正確使用它們來避免競態條件和提高程序效率。同時,我們還將分析線程安全的概念,并通過示例展示如何編寫線程安全的代碼,以確保多線程程序的可靠性和穩定性。隨著對這些概念的深入理解,我們將能夠更加熟練地掌握多線程編程,打造出更加健壯和高效的軟件系統。

一、線程同步

1. 競態條件的概念

競態條件(Race Condition)是并發編程中的一個重要概念,它指的是程序的輸出或行為依賴于事件或線程的時序。在多線程環境中,如果多個線程共享某些數據,并且它們試圖同時讀寫這些數據而沒有適當的同步機制來協調這些操作,就可能出現競態條件

簡單來說,當兩個或更多的線程訪問共享數據,并且至少有一個線程在修改這些數據時,如果線程之間的執行順序會影響最終的結果,那么就存在競態條件。由于線程調度通常由操作系統進行,而且具有一定的隨機性,因此競態條件可能導致程序行為不可預測,有時候甚至非常難以復現和調試

競態條件的一個典型例子是“檢查后行動”(check-then-act)操作,其中線程檢查某個條件(如資源是否可用),然后基于這個條件采取行動。如果在檢查和行動之間的時間窗口內,另一個線程改變了條件(如搶占了資源),那么第一個線程的行動可能基于錯誤的假設。

另一個常見的競態條件是“讀-改-寫”(read-modify-write)操作,這涉及到讀取一個變量的值,對其進行修改,然后寫回新值。如果兩個線程同時執行這樣的操作,而且它們的讀取和寫入操作是交織在一起的,那么最終寫回的值可能只反映了其中一個線程的修改,而另一個線程的修改則丟失了。

為了避免競態條件,我們需要使用線程同步機制,如互斥鎖、信號量、條件變量等,來確保在任何時刻只有一個線程能夠訪問臨界區的代碼。通過這種方式,可以序列化對共享資源的訪問,從而避免不確定的時序和數據沖突,保證程序的正確性和穩定性

2. 線程同步的概念

線程同步是指在多線程環境中,控制不同線程之間的執行順序,確保它們能夠有序地共享資源和協調工作的一系列機制和方法。當多個線程訪問共享資源時,如果沒有適當的同步,就可能發生競態條件(Race Condition),導致數據不一致、程序錯誤甚至崩潰。

為了防止這些問題,線程同步提供了一種方式,使得在任何時刻只有一個線程可以訪問到臨界區(Critical Section)。臨界區是指那些訪問共享資源的代碼段,這些資源可能是內存、文件或者其他外部狀態。通過線程同步,我們可以確保每次只有一個線程可以操作臨界區內的共享資源,從而避免非預期的交互和數據沖突

二、條件變量

條件變量是一種同步原語,它用于線程間的通信,使得一個線程能夠在某個特定條件不滿足時掛起(等待),直到另一個線程更新了這個條件并通知等待的線程。條件變量通常與互斥鎖(mutex)一起使用,以避免競態條件,并確保數據的一致性。

1. 條件變量函數

?使用前提

在Linux環境下,使用條件變量相關的函數需要包含<pthread.h>頭文件:

#include <pthread.h>

<pthread.h> 頭文件中定義了所有與POSIX線程相關的數據類型、函數原型和宏。這包括了條件變量的操作函數、互斥鎖的操作函數以及線程創建和控制的函數。

當編譯使用了 <pthread.h> 的程序時,通常需要鏈接線程庫,這可以通過在編譯命令中添加 -lpthread 選項來實現。例如:

gcc program.c -o program -lpthread

這條命令會編譯 program.c 文件,并將POSIX線程庫鏈接到生成的可執行文件 program 中。

(1)初始化條件變量

在POSIX線程(pthreads)庫中,條件變量可以通過兩種方式進行初始化:

  1. 靜態初始化:使用預定義的宏 PTHREAD_COND_INITIALIZER 來初始化條件變量。這是在程序開始執行之前,即編譯時期就已經完成的初始化。

    示例代碼:

    pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    
  2. 動態初始化:使用函數 pthread_cond_init() 在運行時動態地初始化條件變量。這種方式允許你指定條件變量的屬性。

    示例代碼:

    pthread_cond_t cond;
    int ret = pthread_cond_init(&cond, NULL); // 使用NULL作為屬性參數,表示默認屬性
    if (ret != 0) 
    {// 錯誤處理
    }
    

在動態初始化的情況下,如果你想要設置特定的條件變量屬性,可以創建一個 pthread_condattr_t 類型的變量,并使用 pthread_condattr_init() 和相關函數來設置所需的屬性。之后,將這個屬性變量傳遞給 pthread_cond_init() 函數。

不論是靜態還是動態初始化,初始化后的條件變量都處于未信號化的狀態,等待被 pthread_cond_signal()pthread_cond_broadcast() 函數喚醒。

(2)等待條件滿足

pthread_cond_wait 函數是POSIX線程庫中用于等待條件變量的函數。它的作用是阻塞調用線程直到指定的條件變量被信號化。在等待期間,pthread_cond_wait 會自動釋放與條件變量相關聯的互斥鎖,并且在條件變量被信號化后重新獲取互斥鎖。

pthread_cond_wait函數的原型:

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

參數解釋

  • cond:指向需要等待的條件變量的指針。
  • mutex:指向當前線程已鎖定的互斥鎖的指針,必須在調用pthread_cond_wait之前由線程鎖定。

返回值:

  • 如果函數成功,返回0。
  • 如果失敗,將返回一個錯誤碼(非零值)。

使用說明

  1. 線程在調用pthread_cond_wait之前,必須確保已經鎖定了mutex互斥鎖。
  2. 調用pthread_cond_wait后,線程會阻塞,并且mutex互斥鎖被自動釋放,以允許其他線程操作條件和互斥鎖。
  3. 當其他線程對條件變量調用pthread_cond_signalpthread_cond_broadcast時,等待的線程會被喚醒。
  4. 被喚醒的線程在返回前將重新獲取mutex互斥鎖。這意味著當pthread_cond_wait返回時,線程已經再次鎖定了mutex
  5. 因為可能有多個線程在等待同一個條件變量,所以即使線程被喚醒,也不能假設條件已經滿足。通常需要在循環中調用pthread_cond_wait來重新檢查條件。

示例代碼

// 假設已經聲明并初始化了cond和mutex
pthread_mutex_lock(&mutex);
while (condition_is_not_met) 
{pthread_cond_wait(&cond, &mutex);
}
// 此時condition_is_met為真,可以執行依賴于該條件的代碼
pthread_mutex_unlock(&mutex);

在這個示例中,線程首先鎖定互斥鎖mutex,然后在一個循環中檢查條件是否滿足。如果條件不滿足,線程調用pthread_cond_wait等待條件變量cond。當條件變量被其他線程信號化時,線程將被喚醒,并在重新獲得互斥鎖后繼續執行。

(3)喚醒等待

pthread_cond_broadcastpthread_cond_signal 函數都是用來喚醒等待特定條件變量的線程。它們的區別在于喚醒等待線程的數量。

pthread_cond_broadcast()

pthread_cond_broadcast 函數喚醒所有等待特定條件變量的線程。如果沒有線程在等待,調用此函數不會有任何效果。

函數原型如下

int pthread_cond_broadcast(pthread_cond_t *cond);

參數解釋

  • cond:指向需要廣播信號的條件變量的指針。

返回值

  • 如果函數成功,返回0。
  • 如果失敗,將返回一個錯誤碼(非零值)。
pthread_cond_signal()

pthread_cond_broadcast不同,pthread_cond_signal函數只喚醒一個正在等待特定條件變量的線程。如果有多個線程在等待,系統選擇一個線程喚醒。選擇哪個線程通常取決于線程調度策略,程序員無法控制。

函數原型如下

int pthread_cond_signal(pthread_cond_t *cond);

參數解釋

  • cond:指向需要發送信號的條件變量的指針。

返回值

  • 如果函數成功,返回0。
  • 如果失敗,將返回一個錯誤碼(非零值)。

使用說明

  1. 在調用pthread_cond_signalpthread_cond_broadcast之前,通常需要鎖定與條件變量相關聯的互斥鎖。
  2. 調用這些函數后,互斥鎖可以被釋放,以便喚醒的線程可以繼續執行。
  3. 喚醒的線程將嘗試重新獲取互斥鎖,一旦獲取成功,它們就可以檢查條件是否滿足并繼續執行。

示例代碼

// 假設已經聲明并初始化了cond和mutex
pthread_mutex_lock(&mutex);
// 更新條件并可能修改共享資源
condition_met = 1;
// 喚醒所有等待cond的線程
pthread_cond_broadcast(&cond);
// 或者,只喚醒至少一個等待cond的線程
// pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);

在這個示例中,線程首先鎖定互斥鎖mutex,然后更新條件變量相關的條件。之后,使用pthread_cond_broadcastpthread_cond_signal來喚醒等待該條件變量的線程。最后,線程解鎖互斥鎖。

(4)銷毀條件變量

銷毀條件變量是指在條件變量不再需要時,釋放它所占用的資源。在POSIX線程(pthreads)庫中,可以使用 pthread_cond_destroy 函數來銷毀一個條件變量。

pthread_cond_destroy 函數的原型

int pthread_cond_destroy(pthread_cond_t *cond);

參數解釋

  • cond:指向需要銷毀的條件變量的指針。

返回值

  • 如果函數成功,返回0。
  • 如果失敗,將返回一個錯誤碼(非零值)。

使用說明

  1. 在調用 pthread_cond_destroy 之前,必須確保沒有線程正在等待或即將等待條件變量。否則,行為是未定義的,并且可能會導致程序崩潰或其他錯誤。
  2. 通常,在動態初始化的條件變量不再需要時調用 pthread_cond_destroy。對于靜態初始化的條件變量,如果沒有分配額外的資源,則可以不調用 pthread_cond_destroy
  3. 一旦條件變量被銷毀,你應該避免再次使用它,除非它被重新初始化。

示例代碼

// 假設 cond 是一個之前已經初始化的條件變量
int ret = pthread_cond_destroy(&cond);
if (ret != 0) 
{// 錯誤處理
}

在這個示例中,cond 是一個先前已經初始化并且現在不再需要的條件變量。通過調用 pthread_cond_destroy 來銷毀它,從而釋放可能分配的資源。如果銷毀過程中出現錯誤,可以根據返回的錯誤碼進行相應的錯誤處理。

2. 條件變量使用規范

條件變量的運行機制基于兩個主要操作:等待(wait)和通知(signal/broadcast)

(1)條件變量的使用流程

  1. 等待條件(Waiting for a Condition):

    • 線程首先獲取與條件變量關聯的互斥鎖。
    • 線程檢查某個條件是否滿足。如果條件不滿足,線程將進入等待狀態,并且原子地釋放互斥鎖,這樣其他線程就可以獲取互斥鎖來更改條件。
    • 當條件變量收到通知后,線程被喚醒,重新嘗試獲取互斥鎖。一旦獲取到鎖,線程將再次檢查條件是否滿足,以防在等待期間條件發生了變化。
  2. 通知等待線程(Notifying Waiting Threads):

    • 另一個線程在更改了條件后,會獲取相同的互斥鎖。
    • 在保持互斥鎖的情況下,該線程更新條件。
    • 更新完畢后,線程通過條件變量發送通知,表示條件已經改變。通知操作有兩種形式:
      1. signal:喚醒至少一個等待該條件變量的線程。
      2. broadcast:喚醒所有等待該條件變量的線程。
  3. 重新檢查條件(Rechecking the Condition):

    • 被喚醒的線程在從等待狀態返回時需要重新獲得之前釋放的互斥鎖。
    • 一旦鎖被重新獲得,線程應該再次檢查條件,因為在多個線程等待相同條件的情況下,條件可能已經再次變為假。

(2)條件變量的使用注意事項

  • 使用條件變量時,應當始終與互斥鎖配合使用,以防止競態條件。
  • 必須在修改條件之前獲取互斥鎖,并在修改完畢后釋放互斥鎖。
  • 在等待條件變量時,程序應該處于循環中檢查條件,即使被signalbroadcast喚醒,也應重新檢查條件是否真正滿足。
  • 條件變量的等待和通知操作必須在同一個互斥鎖保護下進行,以確保數據的一致性。

3. 使用條件變量的示例

#include <pthread.h>
#include <stdio.h>// 定義全局的條件變量和互斥鎖
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void *thread_function(void *arg) 
{// 獲取互斥鎖pthread_mutex_lock(&mutex);// 等待條件變量pthread_cond_wait(&cond, &mutex);// 做一些工作...printf("Received signal\n");// 釋放互斥鎖pthread_mutex_unlock(&mutex);return NULL;
}int main() 
{pthread_t thread_id;// 創建新線程pthread_create(&thread_id, NULL, thread_function, NULL);// 做一些工作...sleep(1); // 等待一段時間,模擬工作// 發送信號給等待的線程pthread_cond_signal(&cond);// 等待線程結束pthread_join(thread_id, NULL);// 清理資源pthread_cond_destroy(&cond);pthread_mutex_destroy(&mutex);return 0;
}

這個示例中,主線程創建了一個新線程,并通過條件變量發送信號。新線程在接收到信號后開始執行打印操作。

三、線程安全

1. 概念

線程安全指的是當多個線程同時訪問某個功能、對象或變量時,系統能夠確保這個功能、對象或變量仍然能夠如預期般正常工作。具體來說,一個線程安全的程序對于并發訪問沒有任何副作用,不會出現數據競爭、死鎖等問題,可以正確地處理多線程同時訪問的情況。

2. 常見的線程不安全的情況

線程不安全的情況通常發生在多個線程并發訪問共享資源時,由于缺乏適當的同步或互斥機制,導致出現意外的結果。以下是一些常見的線程不安全的情況:

  1. 競態條件(Race Conditions):當多個線程試圖同時訪問和修改共享的數據,而沒有足夠的同步保護時,會導致競態條件。這可能導致數據損壞或不一致的結果。

  2. 數據競爭(Data Races):當至少兩個線程同時訪問相同的內存位置,其中至少一個是寫操作時,且沒有適當的同步時,就會發生數據競爭。這可能導致未定義的行為和程序崩潰。

  3. 死鎖(Deadlock):當兩個或多個線程互相持有對方所需的資源,并且在等待對方釋放資源時都不釋放自己的資源時,就會產生死鎖。這將導致多個線程永遠無法繼續執行。

  4. 活鎖(Livelock):類似于死鎖,但線程們不斷重試某個操作,卻始終無法取得進展,導致系統無法正常工作。

  5. 非原子操作:當一個操作需要多個步驟完成,而這些步驟中間被其他線程打斷,可能導致數據狀態處于不一致的狀態。

  6. 資源泄露:當線程在使用完資源后沒有正確釋放,導致資源泄露,可能最終耗盡系統資源。

  7. 不一致的狀態:當多個線程并發修改共享狀態時,由于缺乏同步機制,可能導致狀態變得不一致,違反程序的預期行為。

以上情況都代表了典型的線程不安全問題,編寫多線程程序時需要格外注意避免這些問題的發生。為了解決這些問題,可以使用鎖、原子操作、條件變量等同步機制來確保線程安全,以及遵循良好的并發編程實踐。

3. 常見的線程安全的情況

  1. 不可變對象(Immutable Objects):不可變對象在創建后無法被修改,因此多個線程同時訪問不會引發線程安全問題。例如,Java中的String類就是不可變對象。

  2. 線程本地存儲(Thread-Local Storage):每個線程都有自己獨立的變量副本,不會被其他線程共享,從而避免了線程安全問題。可以使用ThreadLocal類來實現線程本地存儲。

  3. 局部變量(Local Variables):局部變量是在每個線程的棧幀中創建的,每個線程擁有自己的副本,不存在線程安全問題。

  4. 同步容器(Synchronized Containers):某些容器類(如Vector、Hashtable)提供了內部同步機制,可以安全地在多線程環境下使用。這些容器會確保對它們的操作是原子的,并且提供了線程安全的迭代器。

  5. 并發容器(Concurrent Containers):Java中的ConcurrentHashMap、ConcurrentLinkedQueue等并發容器提供了高效的線程安全操作。它們使用了復雜的算法和數據結構來實現高性能的并發訪問。

  6. 使用互斥鎖(Mutex)或同步機制:通過在多個線程訪問共享資源時使用互斥鎖、讀寫鎖等同步機制,可以保證線程安全。這樣在任意時刻只有一個線程能夠訪問共享資源。

  7. 原子操作(Atomic Operations):某些編程語言提供了原子操作,這些操作是不可中斷的,可以保證在多線程環境下的原子性。例如,Java中的AtomicInteger類提供了原子操作的整型變量。

  8. 使用并發編程庫和框架:一些現代編程語言和框架提供了豐富的并發編程工具和庫,如Java中的java.util.concurrent包,可以更方便地實現線程安全。

4. 可重入與線程安全的關系(八股文)

(1)可重入與線程安全的聯系

  • 函數是可重入的,那就是線程安全的
  • 函數是不可重入的,那就不能由多個線程使用,有可能引發線程安全問題。
  • 如果一個函數中有全局變量,那么這個函數既不是線程安全也不是可重入的。

(2)可重入與線程安全的區別

  • 可重入函數是線程安全函數的一種。
  • 線程安全不一定是可重入的,而可重入函數則一定是線程安全的。
  • 如果將對臨界資源的訪問加上鎖,則這個函數是線程安全的,但如果這個重入函數若鎖還未釋放則會產生死鎖,因此是不可重入的。

溫馨提示

感謝您對博主文章的關注與支持!如果您喜歡這篇文章,可以點贊、評論和分享給您的同學,這將對我提供巨大的鼓勵和支持。另外,我計劃在未來的更新中持續探討與本文相關的內容。我會為您帶來更多關于Linux以及C++編程技術問題的深入解析、應用案例和趣味玩法等。如果感興趣的話可以關注博主的更新,不要錯過任何精彩內容!

再次感謝您的支持和關注。我們期待與您建立更緊密的互動,共同探索Linux、C++、算法和編程的奧秘。祝您生活愉快,排便順暢!
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210814.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210814.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210814.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JavaGUI詳解

GUI Java GUI**1、Java GUI 概述****2、容器****2、1 窗口****2、2 彈窗和對話框****對話框****自定義彈窗** **2、3 面板****普通面板****滾動面板****分隔面板****選項卡面板** **3、布局****3.1、流式布局****3.2、網格布局****3.3、邊框布局****4、組件****4.1、基本組件**…

Steampipe的安裝部署及簡單使用(附帶AWS CLI的安裝與使用)

介紹 Steampipe 將 API 和服務公開為高性能關系數據庫&#xff0c;使您能夠編寫基于 SQL 的查詢來探索動態數據。Mods 通過使用簡單 HCL 構建的儀表板、報告和控件擴展了 Steampipe 的功能。 官網&#xff1a;https://steampipe.io/ steampipe的安裝 下載腳本并執行 sudo /…

Unity優化——批處理的優勢

大家好&#xff0c;這里是七七&#xff0c;前段時間在忙一些事情&#xff0c;最近終于有空來更新優化篇了。本文本打算分為上下兩篇&#xff0c;但為了看更方便&#xff0c;就多花了幾天寫成一文發布&#xff0c;具體是介紹了圖形優化中批處理的具體效果&#xff0c;雖然本文篇…

【Linux】cat 命令使用

cat 命令 cat&#xff08;英文全拼&#xff1a;concatenate&#xff09;命令用于連接文件并打印到標準輸出設備上。 可以使用cat連接多個文件、創建新文件、將內容附加到現有文件、查看文件內容以及重定向終端或文件中的輸出。 cat可用于在不同選項的幫助下格式化文件的輸出…

LV.13 D1 嵌入式系統移植導學 學習筆記

一、嵌入式系統分層 操作系統&#xff1a;向下管理硬件、向上提供接口 操作系統為我們提供了&#xff1a; 1.進程管理 2.內存管理 3.網絡接口 4.文件系統 5.設備管理 那系統移植是干什么呢&#xff1f; 就是將Linux操作系統移植到基于ARM處理器的開發板中。 那為什么要移植系…

【calcitonin ; 降鈣素 ;降鈣素原】

Parathyroid_Hormone -甲狀旁腺激素 PTH &#xff1b; 特立帕肽&#xff1b;

『OPEN3D』1.8.2 全局ICP配準

前文提到的多種icp方式均需要初始的變換函數作為配準過程的初始值,并在該初始值上進行迭代優化得到結果;那么global icp為前面這些精配準的icp提供了初始變換函數。因此global ICP配準后可視化的點云結果可能沒有完全配準,需要再進行一次精配準操作。 global icp需要對點云提…

lightdb plorasql集合類型新增可變數組

文章目錄 背景集合類型可變數組可變數組示例 背景 在信創適配中&#xff0c;從Oracle遷移過來的存儲過程使用到可變數組。因此在LightDB-X 23.4版本中對現有的集合類型進行了增強&#xff0c;添加了可變數組類型。 集合類型 在LightDB-X 23.4版本開始plorasql支持的集合類型…

【SQL開發實戰技巧】系列(四十八):Oracle12C常用新特性?多分區操作和管理

系列文章目錄 【SQL開發實戰技巧】系列&#xff08;一&#xff09;:關于SQL不得不說的那些事 【SQL開發實戰技巧】系列&#xff08;二&#xff09;&#xff1a;簡單單表查詢 【SQL開發實戰技巧】系列&#xff08;三&#xff09;&#xff1a;SQL排序的那些事 【SQL開發實戰技巧…

K8s構建的mysql無法遠程連接

最近在寫一個老師布置的大作業&#xff0c;都是老師寫好的yaml文件&#xff0c;都是沒問題的&#xff0c;但是構建的mysql無法遠程連接。 嘗試了網上的很多方法&#xff0c;都失敗了&#xff0c;我的構建過程應該是沒什么錯誤的&#xff0c;所以網上的方法并不奏效&#xff0c…

【小白專用】Sql Server 連接Mysql 更新23.12.09

目標 已知mysql連接參數&#xff08;地址和用戶&#xff09;&#xff0c;期望通過Microsoft Sql Server Management Studio &#xff08;以下簡稱MSSSMS&#xff09;連接Mysql&#xff0c;在MSSSMS中直接查詢或修改Mysql中的數據。 一般是選最新的版本下載。 選64位還是32位&a…

C++ 對象的初始化和清理:構造函數和析構函數

目錄 構造函數和析構函數 構造函數 析構函數 構造函數的分類及調用 括號法 顯示法 隱式轉換法 拷貝構造函數的調用時機 使用一個已經創建完畢的對象來初始化一個新對象 值傳遞的方式給函數參數傳值 以值方式返回局部對象 構造函數調用規則 初始化列表 類對象作…

【Java 基礎】27 XML 解析

文章目錄 1.SAX 解析器1&#xff09;什么是 SAX2&#xff09;SAX 工作流程初始化實現事件處理類解析 3&#xff09;示例代碼 2.DOM 解析器1&#xff09;什么是 DOM2&#xff09;DOM 工作流程初始化解析 XML 文檔操作 DOM 樹 3&#xff09;示例代碼 總結 在項目開發中&#xff0…

Jupyter notebook修改背景主題

打開Anaconda Prompt&#xff0c;輸入以下內容 1. pip install --upgrade jupyterthemes 下載對應背景主題包 出現Successfully installed jupyterthemes-0.20.0 lesscpy-0.15.1時&#xff0c;說明已經下載安裝完成 2. jt -l 查看背景主題列表 3. jt -t 主題名稱&#xff08;…

【LeeCode】18.四數之和

給你一個由 n 個整數組成的數組 nums &#xff0c;和一個目標值 target 。請你找出并返回滿足下述全部條件且不重復的四元組 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若兩個四元組元素一一對應&#xff0c;則認為兩個四元組重復&#xff09;&#xff1a; 0 < a, …

mysql的BIT數值類型

MySQL :: MySQL 8.2 Reference Manual :: 11.1.5 Bit-Value Type - BIT MySQL :: MySQL 8.2 Reference Manual :: 9.1.5 Bit-Value Literals BIT類型用來存放bit值&#xff0c;每一位是0或者1&#xff0c;允許1-64位。 例如&#xff0c;下面表定義了new這列的類型為8位的BIT…

NestJS的微服務實現

1.1 基本概念 微服務基本概念&#xff1a;微服務就是將一個項目拆分成多個服務。舉個簡單的例子&#xff1a;將網站的登錄功能可以拆分出來做成一個服務。 微服務分為提供者和消費者&#xff0c;如上“登錄服務”就是一個服務提供者&#xff0c;“網站服務器”就是一個服務消…

Python如何實現數據驅動的接口自動化測試

大家在接口測試的過程中&#xff0c;很多時候會用到對CSV的讀取操作&#xff0c;本文主要說明Python3對CSV的寫入和讀取。下面話不多說了&#xff0c;來一起看看詳細的介紹吧。 1、需求 某API&#xff0c;GET方法&#xff0c;token,mobile,email三個參數 token為必填項mobil…

python在線讀取傳奇列表,并解析為需要的JSON格式

python在線讀取傳奇列表,并解析為需要的JSON格式,以下為傳奇中使用的TXT列表格式, [Server] ; 使用“/”字符分開顏色,也可以不使用顏色,支持以前的舊格式,只有標題和服務器標題支持顏色 ; 標題/顏色代碼(0-255)|服務器標題/顏色代碼(0-255)|服務器名稱|服務器IP|服務器端…

探索人工智能領域——每日20個名詞詳解【day13】

目錄 前言 正文 總結 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高興與大家相識&#xff0c;希望我的博客能對你有所幫助。 &#x1f4a1;本文由Filotimo__??原創&#xff0c;首發于CSDN&#x1f4da;。 &#x1f4e3;如需轉載&#xff0c;請事先與我聯系以…