【Linux】線程周邊002之線程安全

👀樊梓慕:個人主頁

?🎥個人專欄:《C語言》《數據結構》《藍橋杯試題》《LeetCode刷題筆記》《實訓項目》《C++》《Linux》《算法》

🌝每一個不曾起舞的日子,都是對生命的辜負


目錄

前言

1.Linux線程互斥

1.1互斥量的接口

1.1.1初始化互斥量

?1.1.2銷毀動態分配的互斥量

1.1.3互斥量加鎖

1.1.4互斥量解鎖

1.2利用RAII思想封裝一個管理互斥量的對象??

1.3如何保證申請鎖的過程是原子的?

2.Linux線程同步

2.1條件變量

2.1.1初始化條件變量

2.1.2銷毀動態分配的條件變量

2.1.3等待條件變量滿足?

2.1.4喚醒等待的線程

2.2條件變量函數使用規范

3.可重入VS線程安全

3.1概念

3.2常見的線程不安全的情況

3.3常見的線程安全的情況

3.4常見的不可重入的情況

3.5常見的可重入的情況

3.6可重入與線程安全聯系

3.7可重入與線程安全區別

4.常見鎖概念

4.1死鎖

4.2死鎖的四個必要條件


前言

本篇文章內容:線程互斥、互斥量的使用、線程同步、條件變量的使用、可重入函數與線程安全相關內容。

歡迎大家📂收藏📂以便未來做題時可以快速找到思路,巧妙的方法可以事半功倍。?

=========================================================================

GITEE相關代碼:🌟樊飛 (fanfei_c) - Gitee.com🌟

=========================================================================


1.Linux線程互斥

首先我們先來學習一組概念:

  • 臨界資源:?多線程執行流共享的資源叫做臨界資源(全局變量)。
  • 臨界區:?每個線程內部,訪問臨界資源的代碼,就叫做臨界區(訪問或修改臨界資源的代碼)。
  • 互斥:?任何時刻,互斥保證有且只有一個執行流進入臨界區,訪問臨界資源,通常對臨界資源起保護作用。
  • 原子性:?不會被任何調度機制打斷的操作,該操作只有兩態,要么完成,要么未完成。

原子性:如果操作只有一條匯編指令,那么該操作就是原子的。

為了更好的理解,這里模擬實現一個搶票系統,我們將記錄票的剩余張數的變量定義為全局變量,主線程創建四個新線程,讓這四個新線程進行搶票,當票被搶完后這四個線程自動退出。

#include <iostream>
#include <unistd.h>
#include <pthread.h>int tickets = 1000;
void *route(void *arg)
{const char *name = (char *)arg;while (1){if (tickets > 0){usleep(10000);std::cout << name << " get a ticket, remain: " << --tickets << std::endl;}else{break;}}std::cout << name << "quit!" << std::endl;pthread_exit((void *)0);
}
int main()
{pthread_t t1, t2, t3, t4;pthread_create(&t1, NULL, route, (void *)"thread 1");pthread_create(&t2, NULL, route, (void *)"thread 2");pthread_create(&t3, NULL, route, (void *)"thread 3");pthread_create(&t4, NULL, route, (void *)"thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);return 0;
}

?奇怪的是,最后剩余的票數為負值。

我們明明判斷了當tickets>0時,才會對總票數--,可為什么這里是負值呢?

  • if語句判斷條件為真以后,代碼可以并發的切換到其他線程
  • usleep用于模擬漫長業務的過程,在這個漫長的業務過程中,可能有很多個線程會進入該代碼段。
  • --tickets操作本身就不是一個原子操作。

--tickets的操作并不是原子操作,因為它對應著三條匯編指令:

  • load:將共享變量tickets從內存加載到寄存器中。
  • update:更新寄存器里面的值,執行-1操作。
  • store:將新值從寄存器寫回共享變量tickets的內存地址。

要解決以上問題,需要做到三點:?

  • 代碼必須有互斥行為:當代碼進入臨界區執行時,不允許其他線程進入該臨界區。
  • 如果多個線程同時要求執行臨界區的代碼,并且此時臨界區沒有線程在執行,那么只能允許一個線程進入該臨界區。
  • 如果線程不在臨界區中執行,那么該線程不能阻止其他線程進入臨界區。

要做到以上三點,本質上就是需要一把鎖,進入臨界區之前加鎖,離開臨界區后解鎖,Linux上提供的這把鎖叫做互斥量mutex


1.1互斥量的接口

有關于互斥量的操作非常簡單,初始化互斥量,銷毀互斥量,上鎖,解鎖等,并且我們還可以利用RAII的思想來管理動態分配的互斥量,具體如何使用都可以。


1.1.1初始化互斥量

對互斥量的初始化,我們有兩種方式,一種是靜態分配,另一種是動態分配。

靜態分配就是當互斥量是全局或者static時使用:

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//PTHREAD_MUTEX_INITIALIZER是一個宏

對于這種全局或static互斥量,不需要銷毀。


動態分配就是當互斥量是局部時,利用pthread_mutex_init函數初始化,然后使用(動態分配的互斥量需要銷毀):?

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

參數說明:

  • mutex:需要初始化的互斥量。
  • attr:初始化互斥量的屬性,一般設置為nullptr即可。

返回值說明:

  • 互斥量初始化成功返回0,失敗返回錯誤碼。

?1.1.2銷毀動態分配的互斥量

int pthread_mutex_destroy(pthread_mutex_t *mutex);

參數說明:

  • mutex:需要銷毀的互斥量。

返回值說明:

  • 互斥量銷毀成功返回0,失敗返回錯誤碼。

銷毀互斥量需要注意:

  • 使用PTHREAD_MUTEX_INITIALIZER初始化的互斥量不需要銷毀。
  • 不要銷毀一個已經加鎖的互斥量。

1.1.3互斥量加鎖

int pthread_mutex_lock(pthread_mutex_t *mutex);

參數說明:

  • mutex:需要加鎖的互斥量。

返回值說明:

  • 互斥量加鎖成功返回0,失敗返回錯誤碼。

調用pthread_mutex_lock時,可能會遇到以下情況:

  1. 互斥量處于未鎖狀態,該函數會將互斥量鎖定,同時返回成功。
  2. 發起函數調用時,其他線程已經鎖定互斥量,或者存在其他線程同時申請互斥量,但沒有競爭到互斥量,那么pthread_mutex_lock調用會陷入阻塞(執行流被掛起),等待互斥量解鎖。

1.1.4互斥量解鎖

int pthread_mutex_unlock(pthread_mutex_t *mutex);

參數說明:

  • mutex:需要解鎖的互斥量。

返回值說明:

  • 互斥量解鎖成功返回0,失敗返回錯誤碼。

1.2利用RAII思想封裝一個管理互斥量的對象??

#ifndef __LOCK_GUARD_HPP__
#define __LOCK_GUARD_HPP__#include <iostream>
#include <pthread.h>class LockGuard
{
public:LockGuard(pthread_mutex_t *mutex):_mutex(mutex){pthread_mutex_lock(_mutex); // 構造加鎖}~LockGuard(){pthread_mutex_unlock(_mutex);}
private:pthread_mutex_t *_mutex;
};#endif

?有了這個類,你就可以將互斥量交給該類管理,當該類構造時,進行加鎖,當該類析構時解鎖。


1.3如何保證申請鎖的過程是原子的?

上面大家已經意識到了--和++操作不是原子操作,可能會導致數據不一致問題。

其實為了實現互斥鎖操作,大多數體系結構都提供了swap或exchange指令,該指令的作用就是把寄存器和內存單元的數據相交換。

由于只有一條匯編指令,保證了原子性。

加鎖和解鎖的過程我們可以通過下面的偽代碼來理解:

下面我們再以圖示來理解:

?圖示中我們在內存中定義了一個mutex互斥量,當我們進行加鎖時,cpu會原子地將兩個數據進行交換,?交換后,內存中變為0,寄存器%al中變為1,并且這個1的值是唯一的,因為數據在內存中時,所有線程都能訪問,屬于共享的,但是如果轉移到CPU內部寄存器中,就屬于一個線程私有的了,因為CPU寄存器內部的數據是線程的硬件上下文。

所以這個1的值就是唯一的,當任何一個線程將這個1交換走后(交換是原子的),哪怕此時線程的時間片到了被切換走,這個1也被線程作為硬件上下文帶走了,別的線程也拿不到,判斷時也會認為該鎖被占用了。


2.Linux線程同步

同步:?在保證數據安全的前提下,讓線程能夠按照某種特定的順序訪問臨界資源,從而有效避免饑餓問題,這就叫做同步。

那么什么情況下需要同步呢?

如果個別的線程競爭能力非常強,?每次都能夠申請到鎖,但申請到鎖之后什么也不做,所以在我們看來這個線程就一直在申請鎖和釋放鎖,這就可能導致其他線程長時間競爭不到鎖,引起饑餓問題。

那如何解決呢?

我們可以讓線程每次釋放鎖后,不能立即申請鎖,而是去排隊,有順序的申請鎖。


2.1條件變量

條件變量就是實現線程同步的解決方案,是用來描述某種資源是否就緒的一種數據化描述。

換句話說,我們可以利用條件變量實現對其他線程的控制。

比如:

  • 控制某個線程在某一條件變量下等待;
  • 條件滿足后,對該線程進行喚醒。

2.1.1初始化條件變量

對條件變量的初始化,我們有兩種方式,一種是靜態分配,另一種是動態分配。

靜態分配就是當條件變量是全局或者static時使用:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//PTHREAD_COND_INITIALIZER是一個宏

對于這種全局或static互斥量,不需要銷毀。


動態分配就是當條件變量是局部時,利用pthread_cond_init函數初始化,然后使用(動態分配的條件變量需要銷毀):?

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

參數說明:

  • cond:需要初始化的條件變量。
  • attr:初始化條件變量的屬性,一般設置為nullptr即可。

返回值說明:

  • 條件變量初始化成功返回0,失敗返回錯誤碼。

2.1.2銷毀動態分配的條件變量

int pthread_cond_destroy(pthread_cond_t *cond);

參數說明:

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

返回值說明:

  • 條件變量銷毀成功返回0,失敗返回錯誤碼。

銷毀互斥量需要注意:

  • 使用PTHREAD_COND_INITIALIZER初始化的條件變量不需要銷毀。

2.1.3等待條件變量滿足?

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

參數說明:

  • cond:讓線程在該條件變量下等待。
  • mutex:當前線程所處臨界區對應的互斥鎖(為什么要傳互斥鎖???)。

返回值說明:

  • 函數調用成功返回0,失敗返回錯誤碼。

2.1.4喚醒等待的線程

int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

區別:

  • pthread_cond_signal函數用于喚醒等待隊列中首個線程。
  • pthread_cond_broadcast函數用于喚醒等待隊列中的全部線程。

參數說明:

  • cond:喚醒在cond條件變量下等待的線程。

返回值說明:

  • 函數調用成功返回0,失敗返回錯誤碼。

等待條件變量滿足的函數參數為什么要傳互斥鎖?

  • 首先你需要明確的是,使用條件變量一定會搭配使用互斥鎖,因為線程同步的場景本身就是在互斥的前提下,即兩個線程訪問同一資源(臨界資源),而現在需要保證的是資源使用的順序性,所以才引入了條件變量。
  • 而如果此時某個線程由于條件并不滿足(這個條件不滿足一定是臨界資源不滿足該線程運行的條件),被設置了等待條件變量滿足,從而進入了阻塞狀態,能使條件滿足一定是該臨界資源被修改了,從而滿足了線程的運行需要,所以此時你就可以喚醒等待的線程。
  • 也就是說我們想要讓條件得到滿足,就一定會修改臨界資源,而如果你在等待條件變量滿足的時候,仍然持有著該臨界資源的鎖,那么就會導致其他能使該臨界資源滿足線程運行需要的其他線程訪問不了該臨界資源,所以給等待條件變量滿足的函數傳入互斥鎖的目的就是讓這個鎖臨時被釋放,讓其他線程可以訪問該臨界資源

總結:

  • 等待的時候往往是在臨界區內等待的,當該線程進入等待的時候,互斥鎖會自動釋放,而當該線程被喚醒時,又會自動獲得對應的互斥鎖。
  • 條件變量需要配合互斥鎖使用,其中條件變量是用來完成同步的,而互斥鎖是用來完成互斥的。
  • pthread_cond_wait函數有兩個功能,一就是讓線程在特定的條件變量下等待,二就是讓線程釋放對應的互斥鎖。

2.2條件變量函數使用規范

等待條件變量的代碼

pthread_mutex_lock(&mutex);
while (條件為假)pthread_cond_wait(&cond, &mutex);
修改條件
pthread_mutex_unlock(&mutex);

喚醒等待線程的代碼

pthread_mutex_lock(&mutex);
設置條件為真
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);

3.可重入VS線程安全

3.1概念

  • 線程安全: 多個線程并發同一段代碼時,不會出現不同的結果。常見對全局變量或者靜態變量進行操作,并且沒有鎖保護的情況下,會出現線程安全問題。
  • 重入: 同一個函數被不同的執行流調用,當前一個流程還沒有執行完,就有其他的執行流再次進入,我們稱之為重入。一個函數在重入的情況下,運行結果不會出現任何不同或者任何問題,則該函數被稱為可重入函數,否則是不可重入函數。

注意: 線程安全討論的是線程執行代碼時是否安全,重入討論的是函數被重入進入。

3.2常見的線程不安全的情況

  • 不保護共享變量的函數。
  • 函數狀態隨著被調用,狀態發生變化的函數。
  • 返回指向靜態變量指針的函數。
  • 調用線程不安全函數的函數。

3.3常見的線程安全的情況

  • 每個線程對全局變量或者靜態變量只有讀取的權限,而沒有寫入的權限,一般來說這些線程是安全的。
  • 類或者接口對于線程來說都是原子操作。
  • 多個線程之間的切換不會導致該接口的執行結果存在二義性。

3.4常見的不可重入的情況

  • 調用了malloc/free函數,因為malloc函數是用全局鏈表來管理堆的。
  • 調用了標準I/O庫函數,標準I/O可以的很多實現都是以不可重入的方式使用全局數據結構。
  • 可重入函數體內使用了靜態的數據結構。

3.5常見的可重入的情況

  • 不使用全局變量或靜態變量。
  • 不使用malloc或者new開辟出的空間。
  • 不調用不可重入函數。
  • 不返回靜態或全局數據,所有數據都由函數的調用者提供。
  • 使用本地數據,或者通過制作全局數據的本地拷貝來保護全局數據。

3.6可重入與線程安全聯系

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

3.7可重入與線程安全區別

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

可重入函數一定是線程安全的,函數不可重入是引發線程安全問題的一種常見情況。?


4.常見鎖概念

4.1死鎖

死鎖(Deadlock)是數據庫系統、操作系統或并發編程中常見的一種現象,它指的是兩個或兩個以上的進程(或線程)在執行過程中,由于競爭資源或者由于彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法向前推進。此時稱系統處于死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。

舉例:假設有兩個進程P1和P2,它們都需要兩個資源R1和R2。如果P1獲得了R1并請求R2,同時P2獲得了R2并請求R1,那么這兩個進程都會阻塞等待對方釋放資源,從而導致死鎖。

單執行流可能產生死鎖嗎?

單執行流也有可能產生死鎖,如果某一執行流連續申請了兩次鎖,那么此時該執行流就會被掛起。

因為該執行流第一次申請鎖的時候是申請成功的,但第二次申請鎖時因為該鎖已經被申請過了,于是申請失敗導致被掛起直到該鎖被釋放時才會被喚醒,但是這個鎖本來就在自己手上,自己現在處于被掛起的狀態根本沒有機會釋放鎖,所以該執行流將永遠不會被喚醒,此時該執行流也就處于一種死鎖的狀態。

4.2死鎖的四個必要條件

  1. 互斥條件: 一個資源每次只能被一個執行流使用。
  2. 請求與保持條件: 一個執行流因請求資源而阻塞時,對已獲得的資源保持不放。
  3. 不剝奪條件: 一個執行流已獲得的資源,在未使用完之前,不能強行剝奪。
  4. 循環等待條件: 若干執行流之間形成一種頭尾相接的循環等待資源的關系。

注意: 這是死鎖的四個必要條件,也就是說只有同時滿足了這四個條件才可能產生死鎖。

避免死鎖

  • 破壞死鎖的四個必要條件。
  • 按順序申請資源。
  • 避免鎖未釋放的場景。
  • 資源一次性分配。

除此之外,還有一些避免死鎖的算法,比如死鎖檢測算法和銀行家算法。


?=========================================================================

如果你對該系列文章有興趣的話,歡迎持續關注博主動態,博主會持續輸出優質內容

🍎博主很需要大家的支持,你的支持是我創作的不竭動力🍎

🌟~ 點贊收藏+關注 ~🌟

=========================================================================

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

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

相關文章

每日一題——Python實現PAT乙級1050 螺旋矩陣(舉一反三+思想解讀+逐步優化)6千字好文

一個認為一切根源都是“自己不夠強”的INTJ 個人主頁&#xff1a;用哲學編程-CSDN博客專欄&#xff1a;每日一題——舉一反三Python編程學習Python內置函數 Python-3.12.0文檔解讀 目錄 我的寫法 時間復雜度分析 空間復雜度分析 總結 我要更強 代碼解釋 時間復雜度 …

小區服務前臺小程序的設計

管理員賬戶功能包括&#xff1a;系統首頁&#xff0c;個人中心&#xff0c;住戶管理&#xff0c;管理員管理&#xff0c;員工管理&#xff0c;安保管理&#xff0c;安保分配管理&#xff0c;客服聊天管理 微信端賬號功能包括&#xff1a;系統首頁&#xff0c;公告&#xff0c;…

Mongodb集群中的分布式讀寫

學習mongodb&#xff0c;體會mongodb的每一個使用細節&#xff0c;歡迎閱讀威贊的文章。這是威贊發布的第81篇mongodb技術文章&#xff0c;歡迎瀏覽本專欄威贊發布的其他文章。如果您認為我的文章對您有幫助或者解決您的問題&#xff0c;歡迎在文章下面點個贊&#xff0c;或者關…

互聯網摸魚日報(2024-07-01)

互聯網摸魚日報(2024-07-01) 36氪新聞 最前線 | 孚能科技廣州基地投產&#xff0c;年產能30GWh&#xff0c;主推SPS大軟包產品 本周雙碳大事&#xff1a;800億元“風光火儲”大項目來了&#xff1b;光伏巨頭SolarEdge股價驟跌20%&#xff1b;韓國電池廠大火&#xff0c;鋰電安…

目標檢測算法的優缺點

目標檢測算法在計算機視覺領域具有廣泛的應用&#xff0c;其優缺點因算法類型和具體實現而有所不同。以下是對一些主流目標檢測算法優缺點的概述&#xff1a; 1. 傳統目標檢測算法 優點&#xff1a; 模型簡單&#xff1a;傳統目標檢測算法通常基于手工設計的特征和分類器&am…

Java進階學習|Day3.Java集合類(容器),Stream的使用,哈希初接觸

java集合類&#xff08;容器&#xff09; Java中的集合類主要由Collection和Map這兩個接口派生而出&#xff0c;其中Collection接口又派生出三個子接口&#xff0c;分別是Set、List、Queue。所有的Java集合類&#xff0c;都是Set、List、Queue、Map這四個接口的實現類&#xf…

Powershell 簡易爬蟲,提取種子網站的磁力鏈接

目錄 一. 需求二. 分析2.1 思路分析2.2 技術點 三. 代碼四. 效果 一. 需求 ?有網站如下所示&#xff0c;先要求從按照關鍵詞搜索到的網頁中&#xff0c;提取出所有的磁力鏈接。 二. 分析 2.1 思路分析 打開網頁之后&#xff0c;從網頁中先提取出所有的標題相關的url然后再打…

linux驅動部分內容整理

文章目錄 Linux驅動概念應用程序調用驅動程序流程驅動模塊的加載linux設備號加載和卸載注冊新字符設備注冊設備節點自動創建設備節點編譯編譯驅動程序編譯應用程序 地址映射ioctrl命令碼的解析 并發與競爭原子操作自旋鎖信號量互斥體 linux中斷DMA映射其它printkmemcpyvolatile…

如何在ubuntu上安裝ros-noetic?

如何在ubuntu上安裝ros-noetic&#xff1f; 1. 源由2. 快速安裝3. ROS學習 1. 源由 圍繞ros-noetic這個系統&#xff0c;前面已經有不少談及&#xff1a; Linux 35.5 JetPack v5.1.3ros-noetic安裝Linux 35.5 JetPack v5.1.3Fast-Planner編譯安裝Linux 35.5 JetPack v5.1.…

RocketMQ常用基本操作

文章中的rabbitmq使用的是rocketmq-all-5.1.3-bin-release版本&#xff0c;需要安裝包的可自行下載 RockerMQ啟動停止命令 啟動命令 nohup sh bin/mqnamesrv & nohup sh bin/mqbroker -n localhost:9876 --enable-proxy & 查看日志 tail -f ~/logs/rocketmqlogs/…

多線程編程的挑戰與解決方案

多線程編程的挑戰與解決方案 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 1. 多線程編程的挑戰 在現代軟件開發中&#xff0c;多線程編程成為處理并發任務…

PatchTST創新點

這篇論文的創新點主要集中在PatchTST模型的設計和應用中。以下是對其創新點的詳細說明&#xff1a; 創新點 頻道獨立補丁設計&#xff1a;PatchTST模型通過將多變量時間序列分割成不同的頻道&#xff0c;每個頻道作為單變量時間序列處理。每個頻道獨立地通過實例歸一化操作和補…

明星中藥企業系列洞察(九)一手好牌打的稀爛!近500年老字號鎖定退市,太安堂為何“塌房”了?

近日&#xff0c;太安堂發布公告稱&#xff0c;公司已收到深交所下發的《關于廣東太安堂藥業股份有限公司股票終止上市的決定》&#xff0c;深交所決定終止公司股票上市&#xff0c;預計其最后交易日期為7月4日。太安堂曾作為國內知名的中成藥上市公司之一&#xff0c;是國家級…

matlab仿真 通信信號和系統分析(上)

&#xff08;內容源自詳解MATLAB&#xff0f;SIMULINK 通信系統建模與仿真 劉學勇編著第三章內容&#xff0c;有興趣的讀者請閱讀原書&#xff09; 一、求離散信號卷積和 主要還是使用卷積函數conv&#xff0c;值得注意的是&#xff0c;得到的卷積和長度結果為81&#xff0…

node.js+uniapp(vue),阿里云短信驗證碼

reg.vue: 思路是&#xff1a;前端調用獲取驗證碼的接口 > 后端生成驗證碼返回給前端 > 前端渲染驗證碼 <template> <div> <input class"sl-input" v-model"phone" type"tel" maxlength"11" placeholder"手…

微信小程序畢業設計-微信食堂線上訂餐系統項目開發實戰(附源碼+論文)

大家好&#xff01;我是程序猿老A&#xff0c;感謝您閱讀本文&#xff0c;歡迎一鍵三連哦。 &#x1f49e;當前專欄&#xff1a;微信小程序畢業設計 精彩專欄推薦&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python畢業設計…

【在線評論】不同視角下在線評論對客戶滿意度和推薦度的影響—推文分析—2024-07-01

今天的推文主題是【在線評論】&#xff0c;重點關注可以關注第四篇&#xff0c;很全面地分析了在線評論的信息多維性。 第一篇從客戶的在線評論入手&#xff0c;將客戶消費的動機為功利、享受、社會滿足&#xff1b;第二篇是關于在線評論對消費者再次選擇同一家酒店的機制探索…

MySQL之主從同步、分庫分表

1、主從同步的原理 MySQL主從復制的核心是二進制日志 二進制日志&#xff08;binlog&#xff09;記錄了所有DDL語句和DML語句&#xff0c;但不包括數據查詢&#xff08;select、show&#xff09;語句。 1.1、復制分三步 master主庫在事務提交時&#xff0c;會把數據變更記錄…

電子戰學習筆記01:電子戰概論

0、寫在文前 本人在學習電子戰相關理論知識時&#xff0c;一直感覺無從下手&#xff0c;之后在老師的推薦下購買了《EW101&#xff1a;電子戰基礎》紙質書籍學習&#xff0c;所以將自己的學習筆記在CSDN上記錄一下&#xff0c;也供有需要的同學參考。 1、電子戰定義 電子戰&…

Spring Boot與Apache Kafka集成的深度指南

Spring Boot與Apache Kafka集成的深度指南 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 在現代分布式系統中&#xff0c;消息隊列的作用愈發重要&#xff0…