精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Linux多線程同步機制-互斥鎖(mutex)

系統 Linux
在使用互斥鎖時,需要注意正確的加鎖和解鎖順序,避免死鎖等問題。同時,過度使用互斥鎖可能導致性能下降,因為線程可能會因等待鎖而阻塞。因此,在設計多線程程序時,需要仔細考慮互斥鎖的使用位置和時機,以達到最佳的性能和正確性平衡。

引言

在Linux多線程編程中,互斥鎖(Mutex)是一種非常重要的同步機制,用于控制對共享資源的訪問,確保在任意時刻只有一個線程可以訪問特定的資源或代碼段,即臨界區。互斥鎖的主要用途是防止多個線程同時訪問共享資源,從而避免競爭條件和數據不一致的問題。

互斥鎖的工作原理相對簡單,它通過鎖定和解鎖操作來控制對共享資源的訪問。當一個線程需要訪問共享資源時,它首先嘗試鎖定互斥鎖。如果互斥鎖已經被其他線程鎖定,請求線程將被阻塞,直到互斥鎖被解鎖。互斥鎖的鎖定和解鎖操作必須是成對出現的,以確保對共享資源的正確訪問。

一、互斥鎖原型

在 Linux 中,互斥鎖通常通過 POSIX 線程庫(pthread)來實現。pthread 庫提供了一系列的函數來創建、初始化、鎖定、解鎖和銷毀互斥鎖,如pthread_mutex_init()、pthread_mutex_lock()、pthread_mutex_unlock()和pthread_mutex_destroy()等。互斥鎖的初始化是通過pthread_mutex_init()函數完成的,該函數會分配必要的資源來創建一個互斥鎖,并將其初始化為未鎖定狀態。

pthread_mutex_t 是 POSIX 線程庫中用于互斥鎖的數據類型。以下是一些與 pthread_mutex_t 相關的函數原型:

初始化互斥鎖:

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

mutex:指向 pthread_mutex_t 結構的指針,用于初始化互斥鎖。

attr:指向 pthread_mutexattr_t 結構的指針,包含互斥鎖的屬性。如果為 NULL,則使用默認屬性。

銷毀互斥鎖:

int pthread_mutex_destroy(pthread_mutex_t *mutex);
  • mutex:指向已經初始化的 pthread_mutex_t 結構的指針。銷毀互斥鎖前,確保互斥鎖沒有被鎖定。

鎖定互斥鎖:

int pthread_mutex_lock(pthread_mutex_t *mutex);
  • mutex:指向已經初始化的 pthread_mutex_t 結構的指針。如果互斥鎖已經被其他線程鎖定,則調用線程將被阻塞,直到互斥鎖被解鎖。

嘗試鎖定互斥鎖(非阻塞):

int pthread_mutex_trylock(pthread_mutex_t *mutex);
  • mutex:指向已經初始化的 pthread_mutex_t 結構的指針。如果互斥鎖已經被鎖定,則立即返回錯誤碼 EBUSY,而不是等待互斥鎖變為可用。

定時鎖定互斥鎖(可指定超時時間):

int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
  • mutex:指向已經初始化的 pthread_mutex_t 結構的指針。
  • abstime:指向 timespec 結構的指針,包含超時時間。如果超時時間到達,互斥鎖仍未解鎖,則返回 ETIMEDOUT。

解鎖互斥鎖:

int pthread_mutex_unlock(pthread_mutex_t *mutex);
  • mutex:指向已經初始化且當前被調用線程鎖定的 pthread_mutex_t 結構的指針。調用此函數將釋放互斥鎖,允許其他線程鎖定它。

注意:互斥鎖的初始化方式主要有兩種:靜態初始化和動態初始化。

  • 靜態初始化: 使用宏 PTHREAD_MUTEX_INITIALIZER 可以在聲明互斥鎖變量時直接初始化。這種方式是編譯時初始化,無需調用初始化函數。例如:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

這種方式適用于靜態分配的互斥鎖,即在程序的整個生命周期內都存在的鎖。

  • 動態初始化: 使用 pthread_mutex_init() 函數可以在程序運行時初始化互斥鎖。這種方式需要顯式調用函數進行初始化和銷毀,適用于需要動態創建和銷毀的互斥鎖。例如:

pthread_mutex_t *mutex = malloc(sizeof(pthread_mutex_t));pthread_mutex_init(mutex, NULL); // NULL 表示使用默認屬性

使用動態初始化時,需要在不再需要互斥鎖時調用 pthread_mutex_destroy() 來銷毀它,并釋放分配的內存。

互斥鎖的屬性可以在初始化時指定,如果不設置屬性(即使用 NULL 或默認屬性),則使用系統默認的互斥鎖屬性。在Linux系統中,屬性可以用來定義不同類型的互斥鎖,例如:

  • 普通互斥鎖(PTHREAD_MUTEX_TIMED_NP)
  • 遞歸互斥鎖(PTHREAD_MUTEX_RECURSIVE_NP)
  • 錯誤檢查互斥鎖(PTHREAD_MUTEX_ERRORCHECK_NP)
  • 適應性互斥鎖(PTHREAD_MUTEX_ADAPTIVE_NP)

正確初始化互斥鎖對于避免潛在的同步問題是非常重要的。使用靜態初始化可以簡化代碼并減少出錯機會,而動態初始化提供了更大的靈活性。在實際編程中,應根據具體需求選擇適合的初始化方式。

這些函數是 POSIX 線程庫中用于線程同步的基礎,通過它們可以安全地在多線程程序中控制對共享資源的訪問。

三、互斥鎖特性

互斥鎖是一種簡單的加鎖的方法來控制對共享資源的訪問,互斥鎖只有兩種狀態,即上鎖( lock )和解鎖(unlock),如果互斥量已經上鎖,調用線程會阻塞,直到互斥量被解鎖。在完成了對共享資源的訪問后,要對互斥量進行解鎖。

互斥鎖特點如下:

  1. 原子性:把一個互斥量鎖定為一個原子操作,操作系統保證了如果一個線程鎖定了一個互斥量,沒有其他線程在同一時間可以再成功鎖定這個互斥量;
  2. 唯一性:如果一個線程鎖定了一個互斥量,在它解除鎖定之前,沒有其他線程可以鎖定這個互斥量;
  3. 非忙等待:如果一個線程已經鎖定了一個互斥量,第二個線程又試圖去鎖定這個互斥量,則第二個線程將被掛起(不占用任何 cpu 資源),直到第一個線程解除對這個互斥量的鎖定為止,第二個線程則被喚醒并繼續執行,同時鎖定這個互斥量。

四、互斥鎖加鎖阻塞

互斥鎖是一種【獨占鎖】,比如當線程 A 加鎖成功后,此時互斥鎖已經被線程 A 獨占了,只要線程 A 沒有釋放手中的鎖,線程 B 加鎖就會失敗,于是就會釋放 CPU 讓給其他線程,既然線程 B 釋放掉了 CPU,自然線程 B 加鎖的代碼就會被阻塞。

對于互斥鎖加鎖失敗而阻塞的現象,是由操作系統內核實現的。當加鎖失敗時,內核會將線程置為【睡眠】狀態,等到鎖被釋放后,內核會在合適的時機喚醒線程,當這個線程成功獲取到鎖后,于是就可以繼續執行。如下圖:

圖片圖片

所以,互斥鎖加鎖失敗時,會從用戶態陷入到內核態,讓內核幫我們切換線程,雖然簡化了使用鎖的難度,但是存在一定的性能開銷成本。

那這個開銷成本是什么呢?會有兩次線程上下文切換的成本:

  • 當線程加鎖失敗時,內核會把線程的狀態從【運行】狀態設置為【睡眠】狀態,然后把 CPU 切換給其他線程運行;
  • 接著,當鎖被釋放時,之前【睡眠】狀態的線程會變為【就緒】狀態,然后內核會在合適的時間,把 CPU 切換給該線程運行。

線程的上下文切換的是什么?當兩個線程是屬于同一個進程,因為虛擬內存是共享的,所以在切換時,虛擬內存這些資源就保持不動,只需要切換線程的私有數據、寄存器等不共享的數據。

上下切換的耗時有大佬統計過,大概在幾十納秒到幾微秒之間,如果你鎖住的代碼執行時間比較短,那可能上下文切換的時間都比你鎖住的代碼執行時間還要長。

所以,如果你能確定被鎖住的代碼執行時間很短,就不應該用互斥鎖,而應該選用自旋鎖,否則使用互斥鎖。

五、互斥鎖死鎖

互斥鎖導致的死鎖是多線程編程中的一個常見問題。死鎖發生時,兩個或多個線程被無限期地阻塞,因為它們在等待對方釋放鎖。以下是一些關于互斥鎖死鎖的信息:

  1. 死鎖的條件:死鎖通常發生在以下四個條件同時滿足時:

互斥:資源不能被多個線程同時訪問。

占有和等待:一個線程持有至少一個鎖,并且等待獲取其他線程持有的鎖。

不可剝奪:已經獲得的鎖不能被其他線程強行剝奪,只能由持有它的線程釋放。

循環等待:存在一個線程持有鎖的循環鏈,每個線程都在等待下一個線程持有的鎖。

  1. 死鎖的避免:可以通過以下幾種策略來避免死鎖:

固定順序加鎖:總是以相同的順序獲取多個鎖。

超時嘗試加鎖:使用 pthread_mutex_trylock() 或其他帶有超時功能的加鎖方法。

一次性獲取所有鎖:在開始訪問共享資源前,先獲取所有需要的鎖。

使用死鎖檢測算法:定期檢測死鎖情況,并采取措施解決。

  1. 死鎖的解除:如果檢測到死鎖,可以采取以下措施:

剝奪資源:從其他線程剝奪資源,賦予死鎖線程。

撤銷進程:終止一個或多個線程或進程,打破死鎖狀態。

資源重分配:重新分配資源,以打破循環等待條件。

  1. 避免嵌套鎖:盡量減少鎖的嵌套使用,如果必須嵌套使用,確保內層鎖總是不同類型的或者使用不同的加鎖順序。
  2. 鎖的分級管理:將鎖分級,高級別的鎖可以包含多個低級別的鎖,確保在請求高級別鎖時,已經持有所有需要的低級別鎖。

通過采取這些措施,可以降低死鎖發生的風險,并提高多線程程序的穩定性和可靠性。

六、互斥鎖實戰

1.互斥鎖加解鎖

以下是一個簡單的示例代碼,展示了如何在多線程環境中使用 pthread_mutex_t 來同步對同一個文件的讀寫操作:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define NUM_THREADS 5 // 定義宏來設置線程數量

pthread_mutex_t file_mutex = PTHREAD_MUTEX_INITIALIZER; // 全局互斥鎖

const char *data_to_write = "Thread data\n";

void perform_file_write(const char *filename) {
    FILE *fp = fopen(filename, "a");
    if (fp == NULL) {
        perror("Error opening file for write");
        return;
    }

    pthread_mutex_lock(&file_mutex); // 加鎖
    fputs(data_to_write, fp);
    pthread_mutex_unlock(&file_mutex); // 解鎖
    fclose(fp);
}

void perform_file_read(const char *filename) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("Error opening file for read");
        return;
    }

    char buffer[256];
    pthread_mutex_lock(&file_mutex); // 加鎖
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("%s", buffer); // 打印讀取的數據
    }
    pthread_mutex_unlock(&file_mutex); // 解鎖
    fclose(fp);
}

void *thread_function(void *arg) {
    int is_write = *(int *)arg; // 根據傳入的參數決定操作類型
    const char *filename = "example.txt"; // 要操作的文件名

    if (is_write) {
        perform_file_write(filename);
    } else {
        perform_file_read(filename);
    }
    return NULL;
}

int main() {
    int *args = malloc(NUM_THREADS * sizeof(int)); // 動態分配參數數組
    if (args == NULL) {
        perror("Failed to allocate memory for args");
        return 1;
    }

    pthread_t threads[NUM_THREADS];
    for (int i = 0; i < NUM_THREADS; ++i) {
        args[i] = (i == 0); // 第一個線程執行寫操作,其余執行讀操作
        if (pthread_create(&threads[i], NULL, thread_function, &args[i]) != 0) {
            perror("Failed to create thread");
            free(args);
            return 1;
        }
    }

    for (int i = 0; i < NUM_THREADS; ++i) {
        pthread_join(threads[i], NULL);
    }

    free(args); // 釋放參數數組
    // 靜態初始化的互斥鎖不需要顯式銷毀
    return 0;
}

在這個示例中,創建了一個互斥鎖 file_mutex 來同步對文件 example.txt 的訪問。使用 PTHREAD_MUTEX_INITIALIZER 直接初始化互斥鎖,無需再調用pthread_mutex_init 函數了。我們定義了 perform_file_read 和 perform_file_write 函數來執行實際的文件讀寫操作,并在這些操作前后使用 pthread_mutex_lock 和 pthread_mutex_unlock 來確保每次只有一個線程可以訪問文件。在 main 函數中,創建了一個線程數組,并設置第一個線程執行寫操作,其余線程執行讀操作。使用 perror 來打印出創建線程或文件操作失敗時的錯誤信息。最后,我們在主函數中等待所有線程完成,并且由于使用了靜態初始化互斥鎖,我們不需要調用 pthread_mutex_destroy 來銷毀互斥鎖。

程序運行結果如下:

[root@localhost multi_pthread_file]# ./multi_pthread_file_rw
Thread data
Thread data
Thread data
Thread data
[root@localhost multi_pthread_file]# cat example.txt
Thread data

通過程序運行結果可知,我們通過給寫操作和讀操作加互斥鎖,成功實現我們預期的目標,即寫一次數據,讀四次數據。

2.互斥鎖死鎖

以下是一個 C 語言中可能導致死鎖的互斥鎖代碼示例:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t mutex1;
pthread_mutex_t mutex2;

void *thread1Function(void *arg) {
    pthread_mutex_lock(&mutex1);
    printf("Thread 1 acquired mutex1\n");

    sleep(1);

    pthread_mutex_lock(&mutex2);
    printf("Thread 1 acquired mutex2\n");

    pthread_mutex_unlock(&mutex2);
    pthread_mutex_unlock(&mutex1);

    return NULL;
}

void *thread2Function(void *arg) {
    pthread_mutex_lock(&mutex2);
    printf("Thread 2 acquired mutex2\n");

    sleep(1);

    pthread_mutex_lock(&mutex1);
    printf("Thread 2 acquired mutex1\n");

    pthread_mutex_unlock(&mutex1);
    pthread_mutex_unlock(&mutex2);

    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    pthread_mutex_init(&mutex1, NULL);
    pthread_mutex_init(&mutex2, NULL);

    pthread_create(&thread1, NULL, thread1Function, NULL);
    pthread_create(&thread2, NULL, thread2Function, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    pthread_mutex_destroy(&mutex1);
    pthread_mutex_destroy(&mutex2);

    return 0;
}

在這個示例中,thread1 先獲取 mutex1 然后嘗試獲取 mutex2,而 thread2 先獲取 mutex2 然后嘗試獲取 mutex1,可能會導致兩個線程相互等待對方釋放鎖,從而造成死鎖。

【拓展】上文中 sleep(1) 的作用:

在上述代碼中,兩個線程函數中設置 sleep(1) 的主要目的是增加死鎖發生的可能性。當線程獲取一個互斥鎖后,通過 sleep(1) 讓線程暫停一段時間,使得另一個線程有機會去獲取另一個互斥鎖,從而更有可能形成兩個線程相互等待對方持有的鎖的情況,導致死鎖的發生。

如果沒有這個 sleep(1) ,由于線程執行速度非常快,可能在一個線程完成對兩個鎖的獲取和操作之前,另一個線程還沒有機會執行獲取鎖的操作,這樣死鎖就不太容易出現,不利于演示和觀察死鎖的情況。

通過添加 sleep(1) ,模擬了線程操作中的一定延遲,使得線程之間的競爭和等待更加明顯,更有可能展示出死鎖的現象。

編譯并執行可執行程序如下:

[root@localhost multi_pthread_file]# ./dead_lock
Thread 1 acquired mutex1
Thread 2 acquired mutex2

執行可執行程序 dead_lock ,發現該進程在輸出兩條信息后卡住不動,無法繼續執行,出現停滯或長時間無響應的情況,由此推斷該進程死鎖了。

使用 gdb 命令附加到可能發生死鎖的進程。可以通過 ps 命令找到進程 ID(PID),然后使用 gdb 加上進程 ID 來附加到該進程。例如:

[root@localhost multi_pthread_file]# gdb -p 251640 -q
Attaching to process 251640
[New LWP 251641]
[New LWP 251642]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
0x00007fb09e6906cd in __pthread_timedjoin_ex () from /lib64/libpthread.so.0
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-251.el8.x86_64
(gdb) info threads
  Id   Target Id                                      Frame
* 1    Thread 0x7fb09eac8740 (LWP 251640) "dead_lock" 0x00007fb09e6906cd in __pthread_timedjoin_ex () from /lib64/libpthread.so.0
  2    Thread 0x7fb09e2b0700 (LWP 251641) "dead_lock" 0x00007fb09e69885d in __lll_lock_wait () from /lib64/libpthread.so.0
  3    Thread 0x7fb09daaf700 (LWP 251642) "dead_lock" 0x00007fb09e69885d in __lll_lock_wait () from /lib64/libpthread.so.0
(gdb)

使用 info threads 命令列出進程中的所有線程。這將顯示每個線程的 ID 和當前狀態。死鎖的線程通常會顯示為在等待鎖(例如,在 __lll_lock_wait)。根據上述結果可知,該進程已死鎖。

3互斥鎖死鎖檢測和恢復

以下是一個使用 C 語言實現互斥鎖、死鎖檢測和恢復的簡單示例代碼:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>

pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;

int lock1_held = 0;
int lock2_held = 0;

void *thread1(void *arg) {
    pthread_mutex_lock(&lock1);
    printf("Thread 1 acquired lock 1\n");
    lock1_held = 1;

    sleep(1);  // 模擬耗時操作

    while (lock2_held && lock1_held) {  // 持續檢測死鎖條件
        printf("Thread 1 detects potential deadlock and releases lock 1\n");
        pthread_mutex_unlock(&lock1);
        lock1_held = 0;
        sleep(1);  // 等待一段時間后再次嘗試
        pthread_mutex_lock(&lock1);
        lock1_held = 1;
    }

    pthread_mutex_lock(&lock2);
    printf("Thread 1 acquired lock 2\n");

    pthread_mutex_unlock(&lock2);
    pthread_mutex_unlock(&lock1);
    lock1_held = 0;
    lock2_held = 0;

    return NULL;
}

void *thread2(void *arg) {
    pthread_mutex_lock(&lock2);
    printf("Thread 2 acquired lock 2\n");
    lock2_held = 1;

    sleep(1);  // 模擬耗時操作

    while (lock1_held && lock2_held) {  // 持續檢測死鎖條件
        printf("Thread 2 detects potential deadlock and releases lock 2\n");
        pthread_mutex_unlock(&lock2);
        lock2_held = 0;
        sleep(1);  // 等待一段時間后再次嘗試
        pthread_mutex_lock(&lock2);
        lock2_held = 1;
    }

    pthread_mutex_lock(&lock1);
    printf("Thread 2 acquired lock 1\n");

    pthread_mutex_unlock(&lock1);
    pthread_mutex_unlock(&lock2);
    lock1_held = 0;
    lock2_held = 0;

    return NULL;
}

int main() {
    pthread_t t1, t2;

    pthread_create(&t1, NULL, thread1, NULL);
    pthread_create(&t2, NULL, thread2, NULL);

    sleep(5);  // 等待一段時間,讓死鎖有機會發生

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    return 0;
}

在上述示例中,我們進行了如下操作:

1)定義了兩個互斥鎖 lock1 和 lock2,以及兩個標志 lock1_held 和 lock2_held 來跟蹤鎖的持有狀態。

2)thread1 函數:

  • 首先獲取 lock1 并設置相應的標志。
  • 經過一段模擬耗時操作后,進入一個 while 循環,持續檢測是否同時持有 lock1 和 lock2 導致死鎖。
  • 如果檢測到死鎖,打印提示信息,釋放 lock1,將標志重置,等待一段時間后重新獲取 lock1 并再次設置標志。
  • 如果沒有死鎖,獲取 lock2,完成操作后釋放兩個鎖并重置標志。

3)thread2 函數:

  • 與 thread1 函數類似,首先獲取 lock2 并設置標志。
  • 經過模擬耗時操作后,在 while 循環中檢測死鎖情況并進行相應處理。
  • 最終獲取 lock1,完成操作后釋放鎖和重置標志。

4)main 函數:

  • 創建兩個線程分別執行 thread1 和 thread2 函數。
  • 等待一段時間,讓死鎖有機會發生。
  • 等待兩個線程結束。
[root@localhost multi_pthread_file]# ./dead_lock_detect
Thread 1 acquired lock 1
Thread 2 acquired lock 2
Thread 1 detects potential deadlock and releases lock 1
Thread 2 detects potential deadlock and releases lock 2
Thread 1 acquired lock 2
Thread 2 acquired lock 1

通過這種方式,每個線程在獲取第二個鎖之前,持續檢測死鎖情況,并在可能死鎖時采取釋放已持有的鎖、等待后重新嘗試獲取的策略,以盡量避免死鎖的發生。但需要注意的是,這仍然不是一種完全可靠的死鎖避免機制,在復雜的多線程環境中,可能需要更完善的同步和協調策略。

4.固定順序加鎖避免死鎖

以下是一個使用 C 語言實現互斥鎖通過固定加鎖順序來避免死鎖的發生簡單示例代碼:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

// 互斥鎖
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;

// 死鎖檢測標志
int deadlockDetected = 0;

void *thread1Function(void *arg) {
    pthread_mutex_lock(&mutex1);
    printf("Thread 1 acquired mutex1\n");

    sleep(1);

    pthread_mutex_lock(&mutex2);
    printf("Thread 1 acquired mutex2\n");

    pthread_mutex_unlock(&mutex2);
    pthread_mutex_unlock(&mutex1);

    return NULL;
}

void *thread2Function(void *arg) {
    pthread_mutex_lock(&mutex1);
    printf("Thread 2 acquired mutex1\n");

    sleep(1);

    pthread_mutex_lock(&mutex2);
    printf("Thread 2 acquired mutex2\n");

    pthread_mutex_unlock(&mutex2);
    pthread_mutex_unlock(&mutex1);

    return NULL;
}

// 模擬死鎖檢測
void detectDeadlock() {
    sleep(3);
    // 由于固定了加鎖順序,這里不會發生死鎖,無需檢測
}

int main() {
    pthread_t thread1, thread2;

    pthread_mutex_init(&mutex1, NULL);
    pthread_mutex_init(&mutex2, NULL);

    pthread_create(&thread1, NULL, thread1Function, NULL);
    pthread_create(&thread2, NULL, thread2Function, NULL);

    detectDeadlock();

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    pthread_mutex_destroy(&mutex1);
    pthread_mutex_destroy(&mutex2);

    return 0;
}

在上述示例中,我們進行了如下操作:

  1. 首先,定義了兩個互斥鎖 mutex1 和 mutex2,以及一個標志 deadlockDetected 用于死鎖檢測(但在當前代碼中未實際使用)。
  2. thread1Function 和 thread2Function 分別是兩個線程的執行函數。

thread1Function 先獲取 mutex1,等待 1 秒后再獲取 mutex2,最后釋放兩個鎖。

thread2Function 邏輯相同,也是先獲取 mutex1,等待 1 秒后獲取 mutex2,最后釋放。

  1. detectDeadlock 函數用于模擬死鎖檢測,但由于當前固定了加鎖順序,實際上不會發生死鎖,所以此函數內未進行真正的檢測操作。
  2. 在 main 函數中:

初始化兩個互斥鎖。

創建兩個線程分別執行 thread1Function 和 thread2Function 。

調用 detectDeadlock 函數進行死鎖檢測(但如前所述,此處在當前代碼中未實際生效)。

使用 pthread_join 等待兩個線程結束。

最后銷毀兩個互斥鎖。 總的來說,這段代碼創建了兩個線程并嘗試獲取兩個互斥鎖,但由于固定的加鎖順序,不會產生死鎖。

程序運行結果如下:

[root@localhost multi_pthread_file]# ./dead_lock_detect_fixed_mutex
Thread 1 acquired mutex1
Thread 1 acquired mutex2
Thread 2 acquired mutex1
Thread 2 acquired mutex2

通過程序運行結果可知,多個線程使用固定的加鎖順序,不會產生死鎖。

5.pthread_mutex_trylock()函數避免死鎖

以下是一個使用 C 語言實現互斥鎖通過 pthread_mutex_trylock() 來避免死鎖的發生簡單示例代碼:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

pthread_mutex_t lock1, lock2;

void *thread1(void *arg) {
    while (1) {
        // 循環嘗試獲取鎖 1
        if (pthread_mutex_trylock(&lock1) == 0) {
            printf("Thread 1: Acquired lock 1\n");
            break;
        }
        printf("Thread 1: Failed to acquire lock 1, retrying...\n");
        sleep(1);  // 等待一段時間再重試
    }

    // 模擬一些操作
    sleep(1);

    while (1) {
        // 循環嘗試獲取鎖 2
        if (pthread_mutex_trylock(&lock2) == 0) {
            printf("Thread 1: Acquired lock 2\n");
            break;
        }
        printf("Thread 1: Failed to acquire lock 2, retrying...\n");
        pthread_mutex_unlock(&lock1);  // 釋放鎖 1
        sleep(1);  // 等待一段時間再重試
    }

    // 釋放鎖 2 和鎖 1
    pthread_mutex_unlock(&lock2);
    pthread_mutex_unlock(&lock1);

    return NULL;
}

void *thread2(void *arg) {
    while (1) {
        // 循環嘗試獲取鎖 2
        if (pthread_mutex_trylock(&lock2) == 0) {
            printf("Thread 2: Acquired lock 2\n");
            break;
        }
        printf("Thread 2: Failed to acquire lock 2, retrying...\n");
        sleep(1);  // 等待一段時間再重試
    }

    // 模擬一些操作
    sleep(1);

    while (1) {
        // 循環嘗試獲取鎖 1
        if (pthread_mutex_trylock(&lock1) == 0) {
            printf("Thread 2: Acquired lock 1\n");
            break;
        }
        printf("Thread 2: Failed to acquire lock 1, retrying...\n");
        pthread_mutex_unlock(&lock2);  // 釋放鎖 2
        sleep(1);  // 等待一段時間再重試
    }

    // 釋放鎖 1 和鎖 2
    pthread_mutex_unlock(&lock1);
    pthread_mutex_unlock(&lock2);

    return NULL;
}

int main() {
    pthread_t t1, t2;

    // 初始化鎖
    pthread_mutex_init(&lock1, NULL);
    pthread_mutex_init(&lock2, NULL);

    // 創建線程
    pthread_create(&t1, NULL, thread1, NULL);
    pthread_create(&t2, NULL, thread2, NULL);

    // 等待線程結束
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    // 銷毀鎖
    pthread_mutex_destroy(&lock1);
    pthread_mutex_destroy(&lock2);

    return 0;
}

在上述示例中,我們進行了如下操作:

  1. 首先,在程序中定義了兩個互斥鎖 lock1 和 lock2,用于控制線程對資源的訪問。
  2. thread1 函數:

它通過一個無休止的 while 循環來不斷嘗試獲取 lock1 鎖。

一旦成功獲取,會輸出相應的成功獲取信息,并立即跳出當前的循環。

倘若獲取失敗,會輸出失敗提示,并等待 1 秒鐘,然后繼續下一輪的獲取嘗試。

在成功獲取 lock1 之后,經過 1 秒鐘的模擬操作,再次進入另一個 while 循環,嘗試獲取 lock2 。

若獲取 lock2 失敗,會輸出失敗信息,同時釋放之前已獲取到的 lock1 ,接著等待 1 秒鐘,再次進行獲取嘗試。

當成功獲取到 lock2 后,按順序釋放 lock2 和 lock1 ,完成線程的操作。

  1. thread2 函數:

其邏輯與 thread1 相似。首先通過無限的 while 循環嘗試獲取 lock2 。

成功獲取時輸出信息并跳出循環,失敗則輸出提示、等待 1 秒后重新嘗試。

在成功獲取 lock2 并經過 1 秒模擬操作后,進入新的循環嘗試獲取 lock1 。

若獲取 lock1 失敗,同樣輸出失敗提示,釋放 lock2 ,等待 1 秒后重試。

最終成功獲取并按序釋放 lock1 和 lock2 。

  1. main 函數:

聲明了兩個線程變量 t1 和 t2 。

對兩個互斥鎖進行初始化操作。

分別創建兩個線程,讓它們執行 thread1 和 thread2 函數。

使用 pthread_join 函數等待這兩個線程完成執行。

最后,銷毀兩個互斥鎖,釋放相關資源。

這種通過循環嘗試獲取鎖的方式,能夠一定程度上應對獲取鎖失敗的情況,避免線程因單次獲取失敗而直接終止或出現錯誤,增強了程序的穩定性和適應性。但需要注意,這種頻繁的重試可能會帶來一定的系統開銷,所以在實際運用中,要根據具體場景合理設定等待時間和重試策略,以達到性能和可靠性的平衡。

程序運行結果如下:

[root@localhost multi_pthread_file]# ./dead_lock_avoid
Thread 1: Acquired lock 1
Thread 2: Acquired lock 2
Thread 1: Failed to acquire lock 2, retrying...
Thread 2: Failed to acquire lock 1, retrying...
Thread 1: Acquired lock 2
Thread 2: Acquired lock 1

通過程序運行結果可知,多個線程使用 pthread_mutex_trylock 加鎖,可以避免死鎖。

七、總結

互斥鎖(Mutex,Mutual Exclusion Lock)是一種用于多線程環境中的同步機制,具有以下關鍵特點和用途:

  1. 資源保護:確保在同一時刻只有一個線程能夠訪問被保護的共享資源,防止數據競爭和不一致性。
  2. 原子操作:保證對共享資源的操作是原子性的,即要么完全執行,要么完全不執行,避免中間狀態被其他線程觀察到。
  3. 同步協調:使多個線程能夠按照預定的順序和條件進行協作,避免混亂和錯誤。
  4. 互斥性:當一個線程獲取互斥鎖后,其他線程在該鎖被釋放之前無法獲取,從而實現對關鍵代碼段或資源的獨占訪問。

在使用互斥鎖時,需要注意正確的加鎖和解鎖順序,避免死鎖等問題。同時,過度使用互斥鎖可能導致性能下降,因為線程可能會因等待鎖而阻塞。因此,在設計多線程程序時,需要仔細考慮互斥鎖的使用位置和時機,以達到最佳的性能和正確性平衡。

責任編輯:武曉燕 來源: Linux二進制
相關推薦

2024-07-05 08:32:36

2024-07-08 12:51:05

2024-07-25 11:53:53

2020-09-28 06:49:50

Linux系統編程互斥量mutex

2010-01-21 11:27:30

linux多線程機制線程同步

2010-03-15 16:31:34

Java多線程

2020-08-26 08:59:58

Linux線程互斥鎖

2011-11-23 10:09:19

Java線程機制

2021-03-24 08:02:58

C語言

2025-02-17 02:00:00

Monitor機制代碼

2024-06-24 08:10:00

C++互斥鎖

2023-12-24 12:33:20

互斥鎖Go代碼

2025-05-06 08:20:00

互斥鎖C++編程

2023-06-02 08:29:24

https://wwMutex

2023-06-09 07:59:37

多線程編程鎖機制

2025-03-31 00:01:12

2017-12-15 10:20:56

MySQLInnoDB同步機制

2019-05-27 14:40:43

Java同步機制多線程編程

2009-11-28 20:24:13

Linux互斥鎖同步移植

2012-07-27 10:02:39

C#
點贊
收藏

51CTO技術棧公眾號

久久亚洲一区二区三区四区| 91久久国产| 婷婷中文字幕一区三区| 国产精品久久久久久久久婷婷| 亚洲色图 激情小说| 99九九久久| 国产精品久久福利| 国产美女高潮久久白浆| 91插插插插插插| 999国产精品一区| 欧美日韩亚洲精品一区二区三区| 欧美日韩国产精品一卡| 中文字幕免费高清在线观看| 亚洲国产精品久久久久蝴蝶传媒| 精品国精品国产尤物美女| 午夜久久久久久久久久久| 亚洲av永久纯肉无码精品动漫| 亚洲国内自拍| 最新中文字幕亚洲| 深夜视频在线观看| 另类图片综合电影| 亚洲乱码国产乱码精品精98午夜| 狠狠色噜噜狠狠狠狠色吗综合| 亚洲国产av一区二区三区| 国产精品99久久久久久动医院| 欧美精品一区二区精品网| 中文字幕欧美人妻精品一区| gogogogo高清视频在线| 国产日韩影视精品| 91久色国产| 男人天堂视频网| 欧美成人嫩草网站| 亚洲人a成www在线影院| 日韩av加勒比| 主播大秀视频在线观看一区二区| 亚洲黄色性网站| 亚洲不卡1区| 草草视频在线播放| 青青草原综合久久大伊人精品优势 | 欧美一级黄色录像片| 日本xxxxwww| 精品夜夜嗨av一区二区三区| 欧美国产欧美亚洲国产日韩mv天天看完整| 国产交换配乱淫视频免费| 亚洲精品观看| 欧美精品aⅴ在线视频| 精品中文字幕av| 日本在线免费| 久久久国际精品| 精品国产第一页| www.av在线.com| 美腿丝袜在线亚洲一区| 韩剧1988免费观看全集| 2014亚洲天堂| 日韩理论电影| 亚洲香蕉成人av网站在线观看 | 国产亚洲第一页| 国产精品99久久精品| 在线视频中文亚洲| 国产成人无码精品久久二区三| 国产精东传媒成人av电影| 欧美日韩一区二区三区不卡| 欧美成人免费高清视频| 国产h片在线观看| 亚洲国产你懂的| 麻豆映画在线观看| a天堂中文在线官网在线| 国产视频911| 欧美视频观看一区| 男操女在线观看| 2欧美一区二区三区在线观看视频| av噜噜色噜噜久久| 国产色综合视频| 狠狠色丁香久久婷婷综合丁香| 国产精品青草久久久久福利99| 在线免费观看av网址| 性欧美videos另类喷潮| 日本不卡视频在线播放| 中日韩精品视频在线观看| 在线综合视频| 欧洲一区二区视频| 亚洲精品久久久久久久蜜桃| 欧美96一区二区免费视频| 国产美女直播视频一区| 国产精品久久久久久免费| 精品无人码麻豆乱码1区2区| 亚洲一区二区三| 亚洲精品97久久中文字幕| 成人一级片网址| 久久精品日产第一区二区三区乱码 | 一卡二卡在线观看| 国产一区二区精品在线观看| 999视频在线免费观看| 亚洲第一视频在线| av一区二区不卡| 日韩国产美国| 国产日产一区二区| 亚洲女人****多毛耸耸8| 国产一二三区在线播放| 亚洲国产成人二区| 欧美日韩国产bt| 熟妇女人妻丰满少妇中文字幕| 国产精品15p| 精品成人免费观看| 久久精品视频18| 亚洲精品va| 91精品国产99| 无码人妻av免费一区二区三区 | 国产伦精品一区二区三区千人斩| 中文字幕亚洲一区二区三区五十路| 国产精品免费在线视频| 激情婷婷欧美| 国产成人综合av| 亚洲AV无码乱码国产精品牛牛| thepron国产精品| 亚洲综合网中心| heyzo高清国产精品| 欧美亚洲国产怡红院影院| 一级黄色片国产| jazzjazz国产精品久久| 一本色道久久综合亚洲精品小说| 在线观看免费黄色网址| 亚洲经典自拍| 成人写真视频福利网| 亚洲欧美日韩成人在线| 亚洲免费大片在线观看| 无码少妇一区二区三区芒果| 亚洲精品aⅴ| 亚洲欧美日韩中文在线制服| 欧美激情国产精品免费| 美洲天堂一区二卡三卡四卡视频| 精品视频一区二区| 麻豆网站在线免费观看| 亚洲aaa精品| 国产无遮挡猛进猛出免费软件| 国产一区二区三区免费观看在线| 日韩精品在线免费观看视频| 国产在线免费视频| 国产精品1024| 亚洲国产精品女人| 亚洲男人在线| 久久精品91久久香蕉加勒比| 中文字幕一级片| 国产欧美一区二区三区在线老狼| 大香煮伊手机一区| 久久99蜜桃| 国产精品aaa| av在线免费播放网站| 91福利在线观看| 天天躁夜夜躁狠狠是什么心态| 久久精品一区| 日韩久久精品一区二区三区| 三上悠亚国产精品一区二区三区| 日韩精品久久久久| 国产91精品一区| 国产亚洲成aⅴ人片在线观看| 成人一级片网站| 国内精品视频在线观看| 国产精品精品久久久久久| 黄色美女网站在线观看| 欧洲av一区二区嗯嗯嗯啊| 97人妻人人揉人人躁人人| 秋霞午夜av一区二区三区| 午夜精品一区二区在线观看 | 国产在线激情视频| 91精品欧美福利在线观看| 欧美精品成人久久| av在线播放不卡| 成年人黄色片视频| 久久大综合网| ts人妖另类在线| 成人在线黄色电影| 一区二区三区www| 又污又黄的网站| 亚洲激情图片一区| 黄色工厂在线观看| 美女网站色91| 特级黄色录像片| 免费成人蒂法| 国产精品一区二区久久| 国产乱色在线观看| 亚洲成人久久久久| 免费看av在线| 一二三四区精品视频| 国产精品1000部啪视频| 久久成人免费电影| 青草青青在线视频| 欧美久久精品一级c片| 91九色对白| 在线毛片观看| 欧美日本国产在线| 男人的天堂在线| 91精品一区二区三区在线观看| 日产欧产va高清| 国产精品久久99| 中文文字幕文字幕高清| 美腿丝袜亚洲综合| 免费看日本毛片| 亚洲国产精品91| 青青草久久网络| av在线亚洲色图| 国产精品普通话| 日本黄色免费在线| 久久九九免费视频| 黄色片在线看| 亚洲第一页中文字幕| 一区二区日韩视频| 色噜噜久久综合| 精品一区二区三区四| 国产精品视频一区二区三区不卡| 亚洲天堂美女视频| 国产精品中文有码| 手机在线免费观看毛片| 亚洲理论在线| 欧美日韩在线免费观看视频| 自拍亚洲一区| 国产精品视频在线免费观看| 视频91a欧美| 国产激情综合五月久久| 538在线观看| 欧美人与物videos| а√资源新版在线天堂| 色偷偷综合社区| av在线日韩国产精品| 亚洲欧美日韩综合| 蜜桃视频在线观看视频| 亚洲高清免费观看高清完整版| 国产精品爽爽久久久久久| 欧美性一区二区| 性色av一区二区三区四区| 欧美日韩中文字幕在线| 日本熟妇色xxxxx日本免费看| 亚洲欧美日韩精品久久久久| 亚洲综合图片一区| 国产精品乱码人人做人人爱| 国产成人福利在线| 久久久久久99久久久精品网站| 亚洲av成人精品一区二区三区 | 欧美日韩视频在线第一区| 国产伦精品一区二区三区视频我| 午夜精品福利在线| 日本一二三区不卡| 午夜精品福利久久久| 久久精品国产亚洲AV无码麻豆 | 夜夜爽8888| 欧美日韩一区二区欧美激情| 波多野结衣二区三区| 在线观看日韩一区| 成年人晚上看的视频| 色一情一乱一乱一91av| 蜜臀精品一区二区三区| 色八戒一区二区三区| 青青国产在线视频| 欧美三区免费完整视频在线观看| 丰满人妻一区二区三区四区| 欧美在线播放高清精品| 中文字幕1区2区3区| 欧美日本不卡视频| 亚洲天堂avav| 日韩欧美资源站| 成人午夜福利视频| 亚洲国内精品视频| 你懂的视频在线| 色老头一区二区三区| av网站在线免费| 国模吧一区二区三区| 免费h视频在线观看| 全亚洲最色的网站在线观看| 欧美日韩卡一| 999日本视频| 亚洲va久久久噜噜噜久久| 日韩精品另类天天更新| 天堂网在线观看国产精品| 国产成人亚洲综合无码| 国产精品日韩精品欧美精品| 99视频在线视频| 国产精品一二三在| 蜜桃精品成人影片| 亚洲婷婷综合久久一本伊一区| 欧美成人综合色| 日韩欧美aaa| 国产又粗又猛又黄又爽| 亚洲国产成人爱av在线播放| 国产大学生校花援交在线播放| 久久综合伊人77777尤物| 国产色播av在线| 成人国产精品色哟哟| 欧美日韩一区二区三区不卡视频| 日韩在线电影一区| 午夜精品久久久久99热蜜桃导演 | 亚洲黄色在线观看| 92国产在线视频| 欧美激情精品久久久久久黑人 | 人人爽人人爽人人片| 亚洲视频一区二区免费在线观看| 色播视频在线播放| 欧美日韩在线播放一区| 熟妇人妻中文av无码| 久久精视频免费在线久久完整在线看| 日本不卡网站| 亚洲xxx大片| 欧美日韩激情| 国产a级片网站| 精品在线观看视频| 老司机福利av| 亚洲国产精品一区二区久久恐怖片| 在线免费一区二区| 日韩成人免费视频| 国产在线观看91| 国产精品吴梦梦| 亚洲午夜久久| av高清在线免费观看| 国产传媒欧美日韩成人| 纪美影视在线观看电视版使用方法| 午夜国产精品一区| 国产极品久久久| www.美女亚洲精品| 丝袜美腿一区| 久99久在线| 亚洲第一区色| 极品白嫩少妇无套内谢| 亚洲视频在线一区| 在线观看色网站| 国产一区二区三区在线播放免费观看 | 欧美精品一区二区三区免费播放| 粉嫩绯色av一区二区在线观看| 国产高清视频免费在线观看| 91国在线观看| 青青久草在线| 91国内在线视频| 久久久久观看| 玩弄中年熟妇正在播放| 豆国产96在线|亚洲| 青青草精品在线视频| 91麻豆精品国产自产在线观看一区| 国产精品影院在线| 国产精品第一视频| 九色精品91| 丰满人妻中伦妇伦精品app| 97se狠狠狠综合亚洲狠狠| 日本免费观看视| 亚洲黄一区二区| 九色porny自拍视频在线播放 | 天天插天天干天天操| 久久久在线视频| av成人男女| 国产精品裸体瑜伽视频| 97成人超碰视| 狠狠人妻久久久久久综合| 亚洲欧美国产视频| 日韩三区免费| 亚洲成人精品电影在线观看| 美女视频网站黄色亚洲| 国产wwwwxxxx| 欧美一区二区在线播放| 黄色成人在线观看| av一区二区三区在线观看| 国内自拍一区| 亚洲熟妇一区二区三区| 在线观看www91| 1769视频在线播放免费观看| 国产日韩欧美另类| 亚洲欧美一区在线| 日本一区二区在线免费观看| 精品久久久久久久久久久久久| 日色在线视频| 国产精品丝袜久久久久久高清| 国产精品国产三级国产在线观看| 亚洲一区二区偷拍| 亚洲一级二级三级在线免费观看| 色一情一乱一乱一区91av| 欧美在线观看网址综合| 成人6969www免费视频| 中文字幕avav| 欧美日韩国产麻豆| www黄在线观看| caoporen国产精品| 日韩激情中文字幕| a级片在线观看免费| 亚洲国语精品自产拍在线观看| 欧美aaa视频| 日本一本草久p| 91小视频免费观看| 一级淫片免费看| 韩国一区二区电影| 成人在线免费观看视频| 日本xxxx免费| 在线观看视频一区二区| av网址在线看| 欧美一进一出视频| 国产精品99久久久久久久女警| 青青国产在线观看| www国产亚洲精品久久网站| 麻豆一区二区| 中文字幕在线视频一区二区| 欧美日韩一二三四五区| 高清免费电影在线观看| 日本精品国语自产拍在线观看| 国产精品18久久久久久久久 | 国产成人福利片|