walyand學習筆記(九) wl_dispaly_dispatch線程安全分析


wayland中有幾個概念不太好理解,主要是圍繞着wl_display_dispatch容易產生很多問題 。翻了翻源碼,發現dispatch等函數基本上都是圍繞着

struct wl_event_queue來進行的。

 在最早的wl_display_connect中,調用了wl_display_connect_fd;

 

 對應了struct wl_display的兩個queue;

 

 對於wl_display_dispatch

WL_EXPORT int
wl_display_dispatch(struct wl_display *display)
{
    return wl_display_dispatch_queue(display, &display->default_queue);
}

然后就進入了本文的核心內容,分析一下wl_display_dispatch_queue,先貼上源碼:

WL_EXPORT int
wl_display_dispatch_queue(struct wl_display *display,
              struct wl_event_queue *queue)
{
    int ret;

    if (wl_display_prepare_read_queue(display, queue) == -1)
        return wl_display_dispatch_queue_pending(display, queue);

    while (true) {
        ret = wl_display_flush(display);

        if (ret != -1 || errno != EAGAIN)
            break;

        if (wl_display_poll(display, POLLOUT) == -1) {
            wl_display_cancel_read(display);
            return -1;
        }
    }

    /* Don't stop if flushing hits an EPIPE; continue so we can read any
     * protocol error that may have triggered it. */
    if (ret < 0 && errno != EPIPE) {
        wl_display_cancel_read(display);
        return -1;
    }

    if (wl_display_poll(display, POLLIN) == -1) {
        wl_display_cancel_read(display);
        return -1;
    }

    if (wl_display_read_events(display) == -1)
        return -1;

    return wl_display_dispatch_queue_pending(display, queue);
}

 

結合下面的表格來理解這塊函數的真正用意:

函數名 作用 注解
wl_display_dispatch
在display的default queue上,讀取server的event,如果沒有
event會阻塞在此處,直到收到event為止
 線程安全
wl_display_dispatch_queue
 同上,不過是可以指定一個新的event queue,而非在default queue上  
wl_display_dispatch_queue_pending
 把當前pending在in queue(ring buffer)中的events 處理掉,並返回dispatch的event個數

如果沒有pending的events, 會立即返回

wl_display_flush
 將當前pending在out queue中的cmds全部發送給server  
wl_display_roundtrip_queue
 通過wl_display_sync,告知server端,處理完所有request后,通知到client的回調,這個回調是定義在wayland-client.c中的sync_listener, server在sync ack后,這個函數才會返回  
wl_display_roundtrip
 同上,只是在display的default queue上dispatch和等待ack  
wl_display_prepare_read_queue
 判斷指定的event queue中是否是empty,若是返回0,同時使內部的reader_counter++,否則返回-1並且設置errno為EAGAIN  
wl_display_prepare_read
 同上,只是在default queue上去prepare_read_queue  
wl_display_cancel_read
 會使display結構體內部維護的一個引用計數reader_counter--  
wl_display_read_events

 需要在prepare_read返回0后使用,該函數會使內部的reader_counter--,當某個線程調用該函數后,使reader_counter減為0,則觸發真正的從緩沖區中讀取數據,並喚醒其它阻塞在condition_wait的線程;

其它調用該函數但是沒有使reader_counter減為0的調用者將進入condition_wait的狀態,等待被某個wl_display_read_events或者wl_display_cancel_read來喚醒

 
     

 

 綜合下來,我的理解就是:

wl_display_dispatch在wl_prepare_read 和 poll 以及 wl_display_read_events 的配合下,可以實現線程安全,即使在多線程中,也不會因為多次調用這個函數而出現問題

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM