色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

死鎖的現(xiàn)象及原理

科技綠洲 ? 來源:Linux開發(fā)架構(gòu)之路 ? 作者:Linux開發(fā)架構(gòu)之路 ? 2023-11-10 16:32 ? 次閱讀

組件如何放入自己的項(xiàng)目里?把代碼末兩個(gè)Debug部分刪除,在你的項(xiàng)目里添加下面兩句代碼即可使用死鎖檢測(cè)組件。

init_hook();
start_check();

1. 死鎖的現(xiàn)象以及原理

1.1 復(fù)現(xiàn)最簡(jiǎn)單的死鎖

線程A占有鎖1,線程B占有鎖2;此時(shí)線程A想要獲取鎖2,但是鎖2已經(jīng)被線程B占有, 此時(shí)線程A會(huì)休眠等待線程B釋放鎖2后,再去獲得鎖2。可以看到下面的場(chǎng)景,線程B想要獲取鎖1,結(jié)果線程B也休眠去了。這就導(dǎo)致死鎖,鎖1和鎖2永遠(yuǎn)得不到釋放,因?yàn)榫€程A和線程B都在等待另一個(gè)鎖的釋放。這種僵持的狀態(tài),就稱為死鎖。

圖片

正如下面代碼所示,這樣就引發(fā)了死鎖

void *thread_rountine_1(void *args) {
pthread_t selfid = pthread_self();
printf("thread_routine 1 : %ld n", selfid);
pthread_mutex_lock(&mutex_1);
sleep(1);
pthread_mutex_lock(&mutex_2);
pthread_mutex_unlock(&mutex_2);
pthread_mutex_unlock(&mutex_1);
return (void *) (0);
}
void *thread_rountine_2(void *args) {
pthread_t selfid = pthread_self(); //
printf("thread_routine 2 : %ld n", selfid);
pthread_mutex_lock(&mutex_2);
sleep(1);
pthread_mutex_lock(&mutex_1);
pthread_mutex_unlock(&mutex_1);
pthread_mutex_unlock(&mutex_2);
return (void *) (0);
}

1.2 從死鎖中找出檢測(cè)死鎖的規(guī)律

我們來看看下面這張圖,線程A想要獲取線程B的資源,線程B想要獲取線程C的資源,線程C想要獲取線程D的資源,線程D想要獲取線程A的資源,這其實(shí)就構(gòu)成了一個(gè)有向圖的環(huán)路

來看看前面介紹的最簡(jiǎn)單的死鎖,發(fā)現(xiàn)其本直也是構(gòu)成了一個(gè)有向圖的環(huán)路

圖片

來看看非死鎖的場(chǎng)景,只要線程D釋放了mutex4,那么線程C就能獲得鎖,隨后線程C釋放mutex3和4,那么線程B…可以發(fā)現(xiàn),這個(gè)非死鎖的場(chǎng)景,它是一個(gè)有向圖,但這個(gè)圖沒有構(gòu)成環(huán)路。

圖片

過上面三個(gè)場(chǎng)景的分析,我們其實(shí)就可以把死鎖的問題,轉(zhuǎn)換為 有向圖的環(huán)路檢測(cè)。在線程進(jìn)行加鎖前,我們?nèi)ヅ袛嘁幌滤械木€程有沒有構(gòu)成環(huán)路,如果有,則說明現(xiàn)在很有可能會(huì)進(jìn)入死鎖。

2. 檢測(cè)死鎖的前置條件

2.1 有向圖的邊怎么來?

我們現(xiàn)在已經(jīng)知道了死鎖的問題,就轉(zhuǎn)換為 有向圖的環(huán)路檢測(cè)。那么這個(gè)有向圖怎么構(gòu)建?在我們對(duì)mutex1加鎖的時(shí)候,我們?cè)趺粗朗蔷€程A占有mutex1,在對(duì)mutex2加鎖的時(shí)候,怎么知道它已經(jīng)被線程B占有了?我們無(wú)法知道鎖是屬于哪個(gè)線程的。既然連鎖都不知道屬于哪個(gè)線程,哪有如何構(gòu)建出有向圖呢?換言之,我們需要解決:知道當(dāng)前鎖被哪個(gè)線程占用。我們不知道的原因很簡(jiǎn)單,就是mutex和pthread_id沒有一個(gè)對(duì)應(yīng)關(guān)系。

//鎖與線程的信息
struct pair_t {
    unsigned long int th_id;
    enum Type type;

    unsigned long int lock_id;
    int degress;
};

圖片

我們可以做出一個(gè)數(shù)據(jù)結(jié)構(gòu),在加鎖之前,判斷這個(gè)鎖有沒有被別的線程使用,如果沒有,在加鎖之后我們將這個(gè)鎖與本線程綁定,做一個(gè)pair,然后把這個(gè)pair存起來。比如說線程線程A和mutex1綁定,線程B和mutex2綁定了。當(dāng)線程A再次去嘗試對(duì)mutex2加鎖之前,先判斷mutex2是否名花有主?如果有,那有向圖的邊不就來了嗎?不知道讀者有沒有注意到,這一段話都建立在加鎖之前判斷 鎖 是否名花有主。

有一個(gè)非常簡(jiǎn)單粗暴的方法,在加鎖之前調(diào)用一個(gè)函數(shù),加鎖之后調(diào)用一個(gè)函數(shù)。讀者可以想一下,本文是要實(shí)現(xiàn)一個(gè)組件,所謂組件,給別人也能用,難道在一個(gè)項(xiàng)目里面,想要檢測(cè)一下死鎖,去把lock上下全部加兩個(gè)函數(shù)?這顯然不符合我們組件的設(shè)想,我們希望不改變別人的代碼,就能實(shí)現(xiàn)檢測(cè)。

lock_before(self_id, (unsigned long int) mutex);
pthread_mutex_lock(&mutex);
lock_after(self_id, (unsigned long int) mutex);

要想實(shí)現(xiàn)上面的需求,我們可以使用hook。

2.2 hook—>dlsym

hook是什么意思?鉤子,簡(jiǎn)單來說,我們使用hook,可以把系統(tǒng)或第三方庫(kù)提供的函數(shù),替換成我們寫的同名函數(shù),而第三方庫(kù)的函數(shù)則被我們改名,在我們寫的同名函數(shù)里,可以去調(diào)用第三方庫(kù)原來的函數(shù)。

正如下面代碼所示,系統(tǒng)提供的pthread_mutex_lock被改名為pthread_mutex_lock_f。那么我們就可以使用pthread_mutex_lock來當(dāng)作函數(shù)名稱,如此一來,在別的項(xiàng)目里面,我們通過hook就可以進(jìn)行死鎖檢測(cè),而不需要去改代碼了。

hook提供了兩個(gè)接口;1. dlsym()是針對(duì)系統(tǒng)的,系統(tǒng)原始的api。2. dlopen()是針對(duì)第三方的庫(kù)。

/* ******* ******************Hook****************** ******* */

typedef int (*pthread_mutex_lock_t)(pthread_mutex_t *mutex);

pthread_mutex_lock_t pthread_mutex_lock_f;

typedef int (*pthread_mutex_unlock_t)(pthread_mutex_t *mutex);

pthread_mutex_unlock_t pthread_mutex_unlock_f;

static int init_hook() {
    pthread_mutex_lock_f = dlsym(RTLD_NEXT, "pthread_mutex_lock");
    pthread_mutex_unlock_f = dlsym(RTLD_NEXT, "pthread_mutex_unlock");
}


int pthread_mutex_lock(pthread_mutex_t *mutex) {
    pthread_t self_id = pthread_self(); //
    lock_before(self_id, (unsigned long int) mutex);
    pthread_mutex_lock_f(mutex);
    lock_after(self_id, (unsigned long int) mutex);
}

在進(jìn)程的虛擬內(nèi)存空間里面,有一塊代碼段 ,上面代碼中,pthread_mutex_lock_f是一個(gè)函數(shù)指針,實(shí)際上,就是把pthread_mutex_lock_f指向代碼段里系統(tǒng)函數(shù)的入口地址 ,以此來實(shí)現(xiàn)偷天換日。

還需要注意一點(diǎn),這個(gè)#define _GNU_SOURCE要寫在前面,因?yàn)檫@個(gè)就相當(dāng)于一個(gè)開關(guān),在下面的.h文件里面,有#ifdef _GNU_SOURCE的地方。在gcc編譯的時(shí)候后面加上 -ldl。

#define _GNU_SOURCE
#include < dlfcn.h >

3. 有向圖

3.1 有向圖的數(shù)據(jù)結(jié)構(gòu)

下面來看一下結(jié)構(gòu)體的含義

圖片

ertex_list的每一項(xiàng),都是一個(gè)頂點(diǎn),后面鏈表里面存的,都是邊的另一個(gè)點(diǎn)。

圖片

vlock_list的每一項(xiàng),存的都是鎖與線程的信息

圖片

/* ******* ******************Digraph****************** ******* */

enum Type {
    PROCESS, RESOURCE
};
//鎖與線程的信息
struct pair_t {
    unsigned long int th_id;
    enum Type type;

    unsigned long int lock_id;
    int degress;
};
//頂點(diǎn)
struct vertex_t {
    struct pair_t pair;
    struct vertex_t *next;
};

struct task_graph {
    struct vertex_t vertex_list[MAX];
    int vertex_num;

    struct pair_t lock_list[MAX];
    int lock_num;

    pthread_mutex_t mutex;

    int path[MAX + 1];
    int visited[MAX];
    int k;
    int deadlock;
};

struct task_graph *tg = NULL;


//創(chuàng)建一個(gè)vertex
struct vertex_t *create_vertex(struct pair_t pair) {
    struct vertex_t *tex = (struct vertex_t *) malloc(sizeof(struct vertex_t));

    tex- >pair = pair;
    tex- >next = NULL;
    return tex;
}

//查找vertex在list里面的下標(biāo)
int search_vertex(struct pair_t pair) {
    int i = 0;

    for (i = 0; i < tg- >vertex_num; i++) {
        if (tg- >vertex_list[i].pair.type == pair.type && tg- >vertex_list[i].pair.th_id == pair.th_id) {
            return i;
        }
    }

    return -1;
}

//把vertex添加到vertex_list里面
void add_vertex(struct pair_t pair) {
    if (search_vertex(pair) == -1) {
        tg- >vertex_list[tg- >vertex_num].pair = pair;
        tg- >vertex_list[tg- >vertex_num].next = NULL;
        tg- >vertex_num++;
    }
}

//添加邊,把v添加到u的鏈表里
int add_edge(struct pair_t u, struct pair_t v) {
    add_vertex(u);
    add_vertex(v);

    struct vertex_t *cnt = &(tg- >vertex_list[search_vertex(u)]);

    while (cnt- >next != NULL) {
        cnt = cnt- >next;
    }

    cnt- >next = create_vertex(v);
}

//檢查邊是否存在
int verify_edge(struct pair_t u, struct pair_t v) {
    if (tg- >vertex_num == 0) return 0;

    int idx = search_vertex(u);
    if (idx == -1) {
        return 0;
    }

    struct vertex_t *cnt = &(tg- >vertex_list[idx]);

    while (cnt != NULL) {
        if (cnt- >pair.th_id == v.th_id) {
            return 1;
        }
        cnt = cnt- >next;
    }
    return 0;
}

//刪除邊
int remove_edge(struct pair_t u, struct pair_t v) {

    int idx_u = search_vertex(u);
    int idx_v = search_vertex(v);

    if (idx_u != -1 && idx_v != -1) {

        struct vertex_t *cnt = &tg- >vertex_list[idx_u];
        struct vertex_t *remove;

        while (cnt- >next != NULL) {
            if (cnt- >next- >pair.th_id == v.th_id) {
                remove = cnt- >next;
                cnt- >next = cnt- >next- >next;
                free(remove);
                break;
            }
            cnt = cnt- >next;
        }
    }
}

3.2 dfs判斷環(huán)的方法

現(xiàn)在邊也處理好了,鎖與線程的關(guān)系也處理好了,那么我們?nèi)绾稳ヅ袛嘤袥]有環(huán)呢?我們使用DFS來判斷。

圖片

/* ******* ******************check cycle****************** ******* */

//打印
void print_deadlock(void) {
    int i = 0;
    printf("deadlock : ");
    for (i = 0; i < tg- >k - 1; i++) {
        printf("%ld -- > ", tg- >vertex_list[tg- >path[i]].pair.th_id);
    }
    printf("%ldn", tg- >vertex_list[tg- >path[i]].pair.th_id);
}

void print_locklist(void) {
    int i = 0;

    printf("-----------print_locklist----------n");
    for (i = 0; i < tg- >lock_num; i++) {
        printf("threadid : %ld, lockid: %ldn", tg- >lock_list[i].th_id, tg- >lock_list[i].lock_id);
    }
    printf("-----------------------------------n");
}

int DFS(int idx) {
    struct vertex_t *ver = &tg- >vertex_list[idx];
    if (tg- >visited[idx] == 1) {
        tg- >path[tg- >k++] = idx;
        print_deadlock();
        tg- >deadlock = 1;
        return 0;
    }

    tg- >visited[idx] = 1;
    tg- >path[tg- >k++] = idx;

    while (ver- >next != NULL) {
        DFS(search_vertex(ver- >next- >pair));
        tg- >k--;
        ver = ver- >next;
    }

    return 1;
}

//判斷某個(gè)頂點(diǎn)是否成環(huán)
int search_for_cycle(int idx) {
    struct vertex_t *ver = &tg- >vertex_list[idx];
    tg- >visited[idx] = 1;
    tg- >k = 0;
    tg- >path[tg- >k++] = idx;

    while (ver- >next != NULL) {
        int i = 0;
        for (i = 0; i < tg- >vertex_num; i++) {
            if (i == idx) continue;
            tg- >visited[i] = 0;
        }

        for (i = 1; i <= MAX; i++) {
            tg- >path[i] = -1;
        }
        tg- >k = 1;

        DFS(search_vertex(ver- >next- >pair));
        ver = ver- >next;
    }
}

//檢查是否死鎖
void check_dead_lock(void) {
    printf("-----------check deadlock----------n");

    int i;
    tg- >deadlock = 0;
    for (i = 0; i < tg- >vertex_num; i++) {
        if (tg- >deadlock == 1) {
            break;
        }
        //從每個(gè)點(diǎn)都出發(fā)一遍
        search_for_cycle(i);
    }
    if (tg- >deadlock == 0) {
        printf("no deadlockn");
    }

    printf("----------------------------------n");
}

3.3 簡(jiǎn)單測(cè)試一下

可以看到我們的結(jié)果與預(yù)期一致,說明我們的有向圖與判斷環(huán)完成了,那么下面我們就應(yīng)該去寫上鎖前后的函數(shù)了。

/* ******* ******************Debug 2****************** ******* */


int main() {
    tg = (struct task_graph *) malloc(sizeof(struct task_graph));
    tg- >vertex_num = 0;

    struct pair_t v1;
    v1.th_id = 1;
    v1.type = PROCESS;
    add_vertex(v1);

    struct pair_t v2;
    v2.th_id = 2;
    v2.type = PROCESS;
    add_vertex(v2);

    struct pair_t v3;
    v3.th_id = 3;
    v3.type = PROCESS;
    add_vertex(v3);

    struct pair_t v4;
    v4.th_id = 4;
    v4.type = PROCESS;
    add_vertex(v4);


    struct pair_t v5;
    v5.th_id = 5;
    v5.type = PROCESS;
    add_vertex(v5);


    add_edge(v1, v2);
    add_edge(v2, v3);
    add_edge(v3, v4);
    add_edge(v4, v5);
    add_edge(v3, v1);
    add_edge(v5, v1);

    check_dead_lock();
//    search_for_cycle(search_vertex(v1));
}
root@wxf:/tmp/tmp.d4vz2dOyJP# gcc -o deadlock_success deadlock_success.c -lpthread -ldl
root@wxf:/tmp/tmp.d4vz2dOyJP# ./deadlock_success 
-----------check deadlock----------
deadlock : 1 -- > 2 -- > 3 -- > 4 -- > 5 -- > 1
deadlock : 1 -- > 2 -- > 3 -- > 1
----------------------------------
root@wxf:/tmp/tmp.d4vz2dOyJP#

圖片

4. 三個(gè)原語(yǔ)操作

現(xiàn)在有向圖和hook都有了,那么我們?nèi)绾伟阉梨i檢測(cè)出來?換言之,我們?cè)趺词褂胮thread_mutex_lock和pthread_mutex_unlock構(gòu)建有向圖?

在調(diào)用系統(tǒng)提供的lock以前,我們需要檢測(cè)這個(gè)鎖有沒有被別的線程占用,如果被占用,那么我們就需要往圖里面加一條邊。

如果沒有被占用,那么我們就往里面走。也就是說加鎖完,調(diào)用系統(tǒng)提供的lock之后, 我們需要告訴后面的線程,這個(gè)鎖被我占用了,即添加一項(xiàng)pair,供別人lock之前去檢測(cè)。 如果被占用了,然后鎖被釋放,本線程獲取到了這個(gè)以前被占用的鎖,那么我們lock之后,需要把原來添加的一條邊刪除掉,因?yàn)檫@個(gè)鎖已經(jīng)屬于自己了,并且將鎖對(duì)應(yīng)的pair中的th_id改成自己。

在調(diào)用系統(tǒng)提供的unlock之后,解鎖了一個(gè)鎖之后,我們?nèi)タ纯催€有沒有渴望得到這個(gè)鎖的,如果沒有,則將鎖對(duì)應(yīng)的pair置空,如果有,則不管pair。

注意:下面三個(gè)函數(shù),我對(duì)三個(gè)函數(shù)都加鎖了,這里是我的偷懶操作,鎖的粒度較大。如果想優(yōu)化,應(yīng)該放到serch函數(shù)里面,我這里懶得去改了。

int pthread_mutex_lock(pthread_mutex_t *mutex) {
    pthread_t self_id = pthread_self(); 

    lock_before(self_id, (unsigned long int) mutex);
    pthread_mutex_lock_f(mutex);
    lock_after(self_id, (unsigned long int) mutex);
}

int pthread_mutex_unlock(pthread_mutex_t *mutex) {
    pthread_t self_id = pthread_self();

    pthread_mutex_unlock_f(mutex);
    unlock_after(self_id, (unsigned long int) mutex);
}

4.1 lock_before

我們現(xiàn)在把加鎖理解為談戀愛確認(rèn)關(guān)系。在確認(rèn)關(guān)系之前,我們要去看一下這個(gè)女生有沒有男朋友,如果她沒有男朋友,妙哉!那么我們就直接確認(rèn)關(guān)系(lock)吧!如果她有男朋友,那現(xiàn)在還不能和她談戀愛,我們先與她曖昧?xí)崦?add_edge),等著她分手。

void lock_before(unsigned long int thread_id, unsigned long int lock) {
    pthread_mutex_lock_f(&tg- >mutex);

    int idx = search_lock(lock);
//    printf("[lock_before] self_id:%lu lock:%lu lock idx:%d n", thread_id, lock, idx);
    //如果該鎖是第一次則什么都不做
    if (idx != -1) {
        //u是想要加鎖的線程
        struct pair_t u;
        u.th_id = thread_id;
        u.type = PROCESS;
        //把vertex添加到vertex_list里面
        add_vertex(u);
        //v是鎖原來的線程
        struct pair_t v;
        v.th_id = tg- >lock_list[idx].th_id;
        tg- >lock_list[idx].degress++;
        v.type = PROCESS;
        add_vertex(v);

        if (!verify_edge(u, v)) {
            add_edge(u, v); // 把v加入到vertex_list的u的鏈表中
        }
    }

    pthread_mutex_unlock_f(&tg- >mutex);
}

4.2 lock_after

現(xiàn)在我們加鎖完了,也就是談戀愛確認(rèn)關(guān)系了之后,如果我們是她的初戀,那么我們要向全世界宣布(tg->lock_list[empty_lock_idx]):她,是我的女人!如果不是初戀,她被別人宣布過了,那我們就別搞這么浪漫了,把她給我們的備注改成男朋友就好了(tg->lock_list[idx].th_id = thread_id;),并且我們也不需要曖昧聊天了(remove_edge),因?yàn)樗呀?jīng)是我們女朋友了。

void lock_after(unsigned long int thread_id, unsigned long int lock) {
    pthread_mutex_lock_f(&tg- >mutex);

    int idx = search_lock(lock);
//    printf("[lock_after ] self_id:%lu lock:%lu ", thread_id, lock);

    if (idx == -1) {  // 第一次加鎖,找一個(gè)空位lock_list,設(shè)置th_id和lock
        int empty_lock_idx = search_empty_lock(lock);
        tg- >lock_list[empty_lock_idx].th_id = thread_id;
        tg- >lock_list[empty_lock_idx].lock_id = lock;
//        printf("分配lock_list位置 idx:%d n", empty_lock_idx);
        if (empty_lock_idx >= tg- >lock_num) {
            inc(&tg- >lock_num, 1);
        }
    }
    else {
        //u是想要加鎖的線程
        struct pair_t u;
        u.th_id = thread_id;
        u.type = PROCESS;
        //v是鎖原來的線程
        struct pair_t v;
        v.th_id = tg- >lock_list[idx].th_id;
        tg- >lock_list[idx].degress--;
        v.type = PROCESS;
        //刪除邊
        if (verify_edge(u, v)) {
            remove_edge(u, v);
        }
        //設(shè)為本線程
        tg- >lock_list[idx].th_id = thread_id;

//        printf("獲得 lock idx:%d n", idx);
    }

    pthread_mutex_unlock_f(&tg- >mutex);
}

4.3 unlock_after

unlock就相當(dāng)于分手,如果她沒有備胎,那么她就恢復(fù)單身(pair置空),如果她有備胎,那就隨她吧~

void unlock_after(unsigned long int thread_id, unsigned long int lock) {
    pthread_mutex_lock_f(&tg- >mutex);

    int idx = search_lock(lock);
    //如果入度為0,說明沒有別的線程指向該鎖,則把這個(gè)idx位置置空
    if (tg- >lock_list[idx].degress == 0) {
        tg- >lock_list[idx].th_id = 0;
        tg- >lock_list[idx].lock_id = 0;
    }

    pthread_mutex_unlock_f(&tg- >mutex);
}

5. 死鎖檢測(cè)線程的測(cè)試

下面我們來測(cè)試這個(gè)場(chǎng)景。完整代碼在目錄前言中。

圖片

/* ******* ******************Debug 1****************** ******* */
pthread_mutex_t mutex_1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_3 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_4 = PTHREAD_MUTEX_INITIALIZER;

void *thread_rountine_1(void *args) {
    pthread_t selfid = pthread_self(); //

    printf("thread_routine 1 : %ld n", selfid);

    pthread_mutex_lock(&mutex_1);
    sleep(1);
    pthread_mutex_lock(&mutex_2);

    pthread_mutex_unlock(&mutex_2);
    pthread_mutex_unlock(&mutex_1);

    return (void *) (0);
}

void *thread_rountine_2(void *args) {
    pthread_t selfid = pthread_self(); //

    printf("thread_routine 2 : %ld n", selfid);

    pthread_mutex_lock(&mutex_2);
    sleep(1);
    pthread_mutex_lock(&mutex_3);

    pthread_mutex_unlock(&mutex_3);
    pthread_mutex_unlock(&mutex_2);

    return (void *) (0);
}

void *thread_rountine_3(void *args) {
    pthread_t selfid = pthread_self(); //

    printf("thread_routine 3 : %ld n", selfid);

    pthread_mutex_lock(&mutex_3);
    sleep(1);
    pthread_mutex_lock(&mutex_4);

    pthread_mutex_unlock(&mutex_4);
    pthread_mutex_unlock(&mutex_3);

    return (void *) (0);
}

void *thread_rountine_4(void *args) {
    pthread_t selfid = pthread_self(); //

    printf("thread_routine 4 : %ld n", selfid);

    pthread_mutex_lock(&mutex_4);
    sleep(1);
    pthread_mutex_lock(&mutex_1);

    pthread_mutex_unlock(&mutex_1);
    pthread_mutex_unlock(&mutex_4);

    return (void *) (0);
}


int main() {
    init_hook();
    start_check();

    printf("start_checkn");

    pthread_t tid1, tid2, tid3, tid4;
    pthread_create(&tid1, NULL, thread_rountine_1, NULL);
    pthread_create(&tid2, NULL, thread_rountine_2, NULL);
    pthread_create(&tid3, NULL, thread_rountine_3, NULL);
    pthread_create(&tid4, NULL, thread_rountine_4, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_join(tid3, NULL);
    pthread_join(tid4, NULL);

    return 0;
}

圖片

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 死鎖
    +關(guān)注

    關(guān)注

    0

    文章

    25

    瀏覽量

    8079
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4338

    瀏覽量

    62735
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4801

    瀏覽量

    68728
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    505

    瀏覽量

    19705
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    STM32應(yīng)用實(shí)例十:簡(jiǎn)析STM32 I2C通訊死鎖問題

    時(shí)鐘為高,而SDA的電平時(shí)鐘為低。如果拔掉對(duì)應(yīng)的設(shè)備,SCL的波形則恢復(fù)正常。接上設(shè)備恢復(fù)正常,但運(yùn)行一會(huì)現(xiàn)象依舊。一開始以為是連接的設(shè)備有問題,于是換了一臺(tái)設(shè)備,發(fā)現(xiàn)依舊如此。難道真的是I2C出現(xiàn)了死鎖
    發(fā)表于 05-15 13:36

    哪些因素影響了FPGA的并行多通道激勵(lì)信號(hào)產(chǎn)生?

    并行測(cè)試的實(shí)現(xiàn)途徑分為軟件方式和硬件方式。用軟件方式實(shí)現(xiàn)并行測(cè)試,關(guān)鍵是對(duì)測(cè)試任務(wù)的分解和調(diào)度,但可能會(huì)產(chǎn)生競(jìng)爭(zhēng)或者死鎖現(xiàn)象。因此,在測(cè)試資源有限并且任務(wù)分解和調(diào)度算法不成熟的情況下,用軟件實(shí)現(xiàn)并行測(cè)試會(huì)很困難。那么,為什么說對(duì)多通道并行激勵(lì)信號(hào)的需求也是影響并行測(cè)試的關(guān)
    發(fā)表于 08-13 08:08

    FPGA并行多通道信號(hào)產(chǎn)生模塊有什么特點(diǎn)?

    并行測(cè)試的實(shí)現(xiàn)途徑分為軟件方式和硬件方式。用軟件方式實(shí)現(xiàn)并行測(cè)試,關(guān)鍵是對(duì)測(cè)試任務(wù)的分解和調(diào)度,但可能會(huì)產(chǎn)生競(jìng)爭(zhēng)或者死鎖現(xiàn)象。因此,在測(cè)試資源有限并且任務(wù)分解和調(diào)度算法不成熟的情況下,用軟件實(shí)現(xiàn)并行
    發(fā)表于 08-16 06:50

    拔插法與替換法簡(jiǎn)析

    1、拔插法:“拔插法”是將插件“拔出”或“插入”來尋找故障的方法。例如,機(jī)器出現(xiàn)“死鎖現(xiàn)象,采用這種方法一塊一塊地拔出插件板,若機(jī)器恢復(fù)正常,說明故障出在該板上。2、替換法:替換法”是采用已確定是
    發(fā)表于 09-08 06:43

    請(qǐng)問STM32 F103串口同時(shí)收發(fā)出現(xiàn)死鎖現(xiàn)象怎么解決?

    請(qǐng)問STM32 F103串口同時(shí)收發(fā)出現(xiàn)死鎖現(xiàn)象怎么解決?
    發(fā)表于 02-18 07:56

    強(qiáng)干擾下數(shù)據(jù)采集系統(tǒng)穩(wěn)定通訊解決方案

    本文介紹了RS-232 串行總線及USB 通用串行總線技術(shù),討論了其抗干擾性,分析了串口出現(xiàn)誤碼及USB 接口出現(xiàn)死鎖現(xiàn)象的原因,提出了一種強(qiáng)干擾下數(shù)據(jù)采集系統(tǒng)穩(wěn)定通訊的解決方案
    發(fā)表于 06-19 11:55 ?17次下載

    DIN中的死鎖避免和死鎖恢復(fù)

    DIN中的死鎖避免和死鎖恢復(fù) 由于存在占用資源者申請(qǐng)另一個(gè)資源的情形,在DIN中由于拓?fù)浣Y(jié)構(gòu)本身存在環(huán)狀路徑,所以
    發(fā)表于 02-23 14:47 ?921次閱讀
    DIN中的<b class='flag-5'>死鎖</b>避免和<b class='flag-5'>死鎖</b>恢復(fù)

    基于FPGA的并行多通道激勵(lì)信號(hào)產(chǎn)生模塊

    并行測(cè)試的實(shí)現(xiàn)途徑分為軟件方式和硬件方式。用軟件方式實(shí)現(xiàn)并行測(cè)試,關(guān)鍵是對(duì)測(cè)試任務(wù)的分解和調(diào)度,但可能會(huì)產(chǎn)生競(jìng)爭(zhēng)或者死鎖現(xiàn)象。因此,在測(cè)試資源有限并且任務(wù)分解和調(diào)度算法不成熟的情況下,用軟件實(shí)現(xiàn)并行測(cè)試會(huì)很困難。用硬件方式實(shí)現(xiàn)并行測(cè)試時(shí),需
    發(fā)表于 01-21 00:17 ?1196次閱讀
    基于FPGA的并行多通道激勵(lì)信號(hào)產(chǎn)生模塊

    i2c總線的起始和終止的條件

    盡量選用帶復(fù)位輸人的I2C從器件,從I2C總線死鎖產(chǎn)生的原因可以發(fā)現(xiàn)I2C總線死鎖的一個(gè)必要條件是主設(shè)備復(fù)位了而從設(shè)備沒有復(fù)位。如果從設(shè)備選用帶復(fù)位輸入的芯片,將主從設(shè)備的復(fù)位信號(hào)連接在一起,當(dāng)外部產(chǎn)生復(fù)位事件時(shí),主從設(shè)備同時(shí)復(fù)位,這樣就不會(huì)發(fā)生I2C總線
    發(fā)表于 12-06 15:48 ?2.9w次閱讀
    i2c總線的起始和終止的條件

    如何解決PIC單片機(jī)硬件死鎖的問題

    “CMOS的可控硅效應(yīng)”而產(chǎn)生死鎖現(xiàn)象, 依我各人的觀點(diǎn),應(yīng)與 “CMOS的可控硅效應(yīng)”無(wú)關(guān),但很多大蝦皆認(rèn)為是“CMOS的可控硅效應(yīng)”所引起的。
    發(fā)表于 02-22 15:23 ?3058次閱讀

    STM32 F103串口同時(shí)收發(fā)出現(xiàn)死鎖問題解決辦法

    一直使用F4系列,沒有出現(xiàn)此類現(xiàn)象,也可能出現(xiàn)了沒有發(fā)現(xiàn)。最近在做和研華工控機(jī)通訊時(shí)出現(xiàn)串口接收問題。總結(jié)如下:1. 使用DMA+空閑中斷未出現(xiàn)串口同時(shí)收發(fā)死鎖現(xiàn)象,但是由于研華某款工控機(jī)在與板子
    發(fā)表于 12-24 18:40 ?1次下載
    STM32 F103串口同時(shí)收發(fā)出現(xiàn)<b class='flag-5'>死鎖</b>問題解決辦法

    為什么說線程是輕量級(jí)的概念呢?守護(hù)線程是指什么?

    當(dāng)多個(gè)線程同時(shí)搶多把鎖的時(shí)候就會(huì)出現(xiàn)死鎖現(xiàn)象。其實(shí)遞歸鎖也不是一個(gè)很好地解決方案,死鎖現(xiàn)象的發(fā)生不是互斥鎖的原因,而是程序猿/媛的邏輯出現(xiàn)了問題。
    的頭像 發(fā)表于 08-19 10:39 ?2090次閱讀
    為什么說線程是輕量級(jí)的概念呢?守護(hù)線程是指什么?

    Linux內(nèi)核死鎖lockdep功能

    死鎖是指兩個(gè)或多個(gè)進(jìn)程因爭(zhēng)奪資源而造成的互相等待的現(xiàn)象,如進(jìn)程A需要資源X,進(jìn)程B需要資源Y,而雙方都掌握對(duì)方所需要的資源,且都不釋放,這會(huì)導(dǎo)致死鎖。 在內(nèi)核開發(fā)中,時(shí)常要考慮并發(fā)設(shè)計(jì),即使采用正確
    的頭像 發(fā)表于 09-27 15:13 ?731次閱讀
    Linux內(nèi)核<b class='flag-5'>死鎖</b>lockdep功能

    死鎖的產(chǎn)生因素

    一、死鎖的概念 操作系統(tǒng)中的死鎖是指: 如果在一個(gè)進(jìn)程集合中的每個(gè)進(jìn)程都在等待只能有該集合中的其它進(jìn)程才能引起的事件,而無(wú)限期陷入僵持的局面稱為死鎖。 二、死鎖的產(chǎn)生因素 1、系統(tǒng)擁有
    的頭像 發(fā)表于 11-09 09:37 ?1314次閱讀
    <b class='flag-5'>死鎖</b>的產(chǎn)生因素

    死鎖現(xiàn)象以及原理

    。 init_hook (); start_check (); 1. 死鎖現(xiàn)象以及原理 1.1 復(fù)現(xiàn)最簡(jiǎn)單的死鎖 線程A占有鎖1,線程B占有鎖2;此時(shí)線程A想要獲取鎖2,但是鎖2已經(jīng)被線程B占有, 此時(shí)線程
    的頭像 發(fā)表于 11-13 16:30 ?553次閱讀
    <b class='flag-5'>死鎖</b>的<b class='flag-5'>現(xiàn)象</b>以及原理
    主站蜘蛛池模板: 日本50人群体交乱| 国产激情视频在线观看| 超碰免费视频公开97| 国产亚洲日韩另类在线播放| 芒果视频看片在线观看| 亚洲AV无码乱码国产麻豆穿越| 99久久夜色精品国产亚洲AV卜| 国产一区日韩二区欧美三区| 欧美伦理片第7页| 伊人久久伊人| 国产精品一久久香蕉国产线看 | 九九热在线视频精品店| 日日摸天天添天天添无码蜜臀| 在线观看精品视频看看播放| 国产精品人妻在线观看| 青柠在线观看视频在线高清| 尤物国产在线精品三区| 国产午夜一区二区三区免费视频| 泡妞高手在都市完整版视频免费| 伊人色综合久久天天网| 国产一区二区青青精品久久| 日韩精品真人荷官无码| 99久久国内精品成人免费| 久久久久久久久女黄| 亚洲大爷操| 国产精品VIDEOSSEX久久发布| 欧美成人免费一区二区三区不卡| 曰本少妇高潮久久久久久| 国产亚洲日韩欧美视频| 涩涩游戏盒| 岛国在线无码免费观| 欧美日韩精品一区二区三区高清视频 | 九九免费高清在线观看视频| 我与恶魔的h生活ova| 超碰人人澡人人胔| 暖暖视频免费观看高清完整版 | 久久久久激情免费观看| 亚洲狠狠网站色噜噜| 国产精品点击进入在线影院高清| 青柠在线观看免费高清电视剧荣耀 | 国产精品久AAAAA片|