0

ユーザー空間でCのリングバッファ実装を探しているので、ライブラリで使用できます。

リングバッファが必要なので

  • ブロックされていない書き込み (=最も古いデータを上書きする)
  • 空の場合は読み取りをブロック

wait_event_interruptibleしばらく検索して、 &wake_up_interruptibleを使用してカーネルモードでこのようなことをしたことを思い出しました。

しかし、ユーザー空間で何が使用されているので、その方法と組み合わせてリングバッファを検索できるでしょうか? 車輪の再発明はしたくありません - 周りには多くのリングバッファソリューションがあります。

よろしくお願いします。

編集:

pthread_cond_wait相当する可能性があるようですwait_event_interruptible

4

2 に答える 2

6

私の他の回答では、疑似コードと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;
}
于 2013-02-07T19:44:07.537 に答える
0

pthreads では、標準的な方法は、mutexを使用し、条件変数を使用して、別のスレッドによって起動されるまで1 つのスレッドで待機することです。

ライターが一時的にブロックされますが、不確定な時間ブロックされることはなく、未読データを破棄することでバッファ オーバーフローが処理される疑似コード:

ライター 書く:

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

上記で明らかなように、ライターは一時的にミューテックスをブロックする可能性がありますが、リーダーは一時的にミューテックスを保持するだけなので (これはバッファー内のデータがかなり短いことを前提としています)、おそらく問題にはなりません。

上記のコードを理解するための重要な詳細: 条件変数とミューテックスはペアとして機能します。条件変数を待機するとミューテックスのロックが解除され、ウェイクアップされると、ミューテックスを再ロックできるようになった後にのみ続行されます。したがって、ライターがミューテックスのロックを解除するまで、リーダーは実際には続行しません。

条件変数の待機が戻ったときにバッファの位置を再度確認することが重要です。また、データを追加しただけのライターによってウェイクアップが行われたと盲目的に信じないでください。

于 2013-02-05T09:42:12.643 に答える