簡體   English   中英

循環/環形緩沖區具有阻塞讀取和非阻塞寫入?

[英]Circular-/Ring-Buffer with blocking read and non-blocking write?

我正在用戶空間中的C中搜索環形緩沖區實現,因此可以在我的庫中使用它。

因為我需要一個ringbuffer

  • 無阻塞寫入(=覆蓋最早的數據)
  • 如果為空則阻止讀取

我搜索了一會兒,並想起我曾經在內核模式下使用過wait_event_interruptiblewake_up_interruptible來做類似的事情。

但是在用戶空間中使用了什么,因此我可能可以結合該方法搜索環形緩沖區? 我不想重新發明輪子-周圍有很多ringbuffer解決方案。

在此先感謝您的光臨!

編輯:

似乎pthread_cond_wait可能等效於wait_event_interruptible

用一些代碼添加另一個答案,與我的另一個答案中的偽代碼不是1:1匹配。 如果有人要添加評論或進行其他改進,請將其標記為Wiki答案。 C phtread互斥鎖+條件變量的實現非常簡單的環形緩沖區:

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

#define RINGBUFFER_SIZE (5)
int ringbuffer[RINGBUFFER_SIZE];
unsigned reader_unread = 0;
unsigned writer_next = 0;
pthread_mutex_t ringbuffer_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t ringbuffer_written_cond = PTHREAD_COND_INITIALIZER;

void process_code(int ch) {
    int counter;
    printf("Processing code %d", ch);
    for(counter=5; counter>0; --counter) {
        putchar('.');
        fflush(stdout);
        sleep(1);
    }
    printf("done.\n");

}

void *reader() {
    pthread_mutex_lock(&ringbuffer_mutex);
    for(;;) {
        if (reader_unread == 0) {
            pthread_cond_wait(&ringbuffer_written_cond, &ringbuffer_mutex);
        }
        if (reader_unread > 0) {

            int ch;
            int pos = writer_next - reader_unread;
            if (pos < 0) pos += RINGBUFFER_SIZE;
            ch = ringbuffer[pos];
            --reader_unread;

            if (ch == EOF) break;

            pthread_mutex_unlock(&ringbuffer_mutex);
            process_code(ch);
            pthread_mutex_lock(&ringbuffer_mutex);
        }
    }
    pthread_mutex_unlock(&ringbuffer_mutex);

    puts("READER THREAD GOT EOF");
    return NULL;
}

void *writer() {
    int ch;
    do {
        int overflow = 0;
        ch = getchar();

        pthread_mutex_lock(&ringbuffer_mutex);

        ringbuffer[writer_next] = ch;

        ++writer_next;
        if (writer_next == RINGBUFFER_SIZE) writer_next = 0;

        if (reader_unread < RINGBUFFER_SIZE) ++reader_unread;
        else overflow = 1;

        pthread_cond_signal(&ringbuffer_written_cond);
        pthread_mutex_unlock(&ringbuffer_mutex);

        if (overflow) puts("WARNING: OVERFLOW!");

    } while(ch != EOF);

    puts("WRITER THREAD GOT EOF");
    return NULL;
}

int main(void)
{
    pthread_t reader_thread, writer_thread;

    puts("Starting threads. Type text and press enter, or type ctrl-d at empty line to quit.");
    pthread_create(&reader_thread, NULL, reader, NULL);
    pthread_create(&writer_thread, NULL, writer, NULL);

    pthread_join(writer_thread, NULL);
    pthread_join(reader_thread, NULL);

    return 0;
}

對於pthreads,標准方法是使用互斥鎖並使用條件變量在一個線程中等待,直到被另一個 線程 喚醒

偽代碼,其中寫程序將短暫阻塞,但不會無限期地阻塞,並且通過丟棄未讀數據來處理緩沖區溢出:

作家寫:

acquire new data to write
lock mutex
get current writing position in buffer
compare to current reading position and check for overflow
    in case of overflow, update reading position (oldest data lost)
write new data to buffer
update writing position
do wakeup on condition variable
unlock mutex

讀者閱讀:

lock mutex
loop:
    get current reading position in buffer
    compare to current writing position in buffer
    if there's new data, break loop
    wait (possibly with timeout) on condition variable
    goto loop:
copy data from buffer
update reading position
unlock mutex
process copied data

顯然,在上面,編寫器可能會短暫阻塞互斥鎖,但是由於讀取器只會短暫持有互斥鎖(假定緩沖區中的數據很短),因此這可能不是問題。

有關理解上述代碼的重要詳細信息:條件變量和互斥體可以成對使用。 等待條件變量將解鎖互斥鎖,並且一旦喚醒,只有在可以重新鎖定互斥鎖之后才會繼續。 因此,在寫入者解鎖互斥鎖之前,讀取者實際上不會繼續。

重要的是在條件變量等待返回時再次檢查緩沖區位置,而不是盲目地相信喚醒是由寫入程序完成的,寫入程序只會向其中添加更多數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM