Dies Aliquanti

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

ThreadでFIFO扱う -S/P DIFの経由の録音の続き番外編

 refer http://onishi-lab.jp/programming/thread_linux.html
ここりらあたりに書かれていることを参考にして、fifoを扱う仕掛けを書いてみた(fifo1.c)。
 要は、スレッドの開始はpthread_create(),終了待ちはpthread_join()をつかうようだ。あと、mutexはクリティカル・リージョンに入るとき、pthread_mutex_lock()、出る時にpthread_mutex_unlock()をつかうということ。

 最後に貼り付けたfifo1.cはとりあえずちゃんと動作するようです。

 リード、ライトのindexとフル、エンプティ判定がちょっとわかりにくい&計算コストが高そうと思うかもしれません。もともとはVerilog-HDLで書いたfifoを、長さが2のべぎ乗以外でも使えるように、拡張というか一般化したもの。fifoの長さが2のべき乗ならば、%(剰余)計算はビットアンドでできますし、isFull()のなかの_rPtrの計算は最上位ビットの反転に相当します。インデックスの範囲をバッファの数の倍まで数えるのが巧妙なところです。
フルやエンプティのチェックをしたあと、usleep()とか「ちょっと待つ」ことをしているのがややダサいですね。fifoのフル/エンプティに対してlock(=mutex)を用意して、

push()の動作は
 フルmutexをロック(既にfifoがフルならばこの時点でスレッドはブロックされる)
 実際にデータをpush
 エンプティmutexをアンロック
 フルでなければフルmutexをアンロック

pop()の方は
 エンプティmutexをロック(既にfifoがエンプティならばこの時点でスレッドはブロックされる)
 実際にデータをpop
 フルmutexアンロック
 エンプティでなければエンプティをアンロック

とかすればよさそう・・・

---fifo1.c---
// refer http://onishi-lab.jp/programming/thread_linux.html
// gcc file_name.c -lpthread

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

// FIFO control
#define FIFOSIZE (256)
typedef int DATA ;

static DATA fifo[FIFOSIZE] ;
static int wPtr = 0, rPtr = 0 ;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void copyData( DATA *from, DATA *to ) {
  // this is prototype
  *to = *from ;
}

//
// inc() must be called inside of critical region
//
void inc( int *p ) {
  int a ;
  a = (*p) + 1;
  *p = a % (FIFOSIZE * 2) ;
}

int isFull( void ) {
  int _rPtr, res ;
  pthread_mutex_lock( &mutex);
  _rPtr = rPtr + (FIFOSIZE  ) ;
  _rPtr = _rPtr % (FIFOSIZE * 2) ;
  res = ( _rPtr == wPtr ) ;
  pthread_mutex_unlock( &mutex);
  /******************
  if (res) {
    printf("FIFO is full %d %d,%d\n", _rPtr, rPtr, wPtr) ;
  } else {
    printf("FIFO is not full %d %d,%d\n", _rPtr, rPtr, wPtr) ;
  }
  *******************/
  return ( res ) ;
}

int isEmpty( void ) {
  int res ;
  pthread_mutex_lock( &mutex);
  res = (rPtr == wPtr ) ;
  pthread_mutex_unlock( &mutex);
  /******************
  if (res) {
    printf("FIFO is Empty\n") ;
  } else {
    printf("FIFO is not Empty\n") ;
  }
  *******************/
  return res ;
}

void push( DATA *p ) {
  int ptr;
  ptr = wPtr % FIFOSIZE ;
  pthread_mutex_lock( &mutex);
  // start of writing data to buffer
 
  copyData( p, &(fifo[ ptr ])) ;
  // end of writing data to buffer
  if( (++wPtr) >=  (FIFOSIZE * 2)) {
    wPtr = 0 ;
  }
  pthread_mutex_unlock( &mutex);
  printf("push %d %d\n", ptr, (int) *p ) ;
}

void pop ( DATA *p ) {
  int ptr;
  ptr = rPtr % FIFOSIZE ;
  pthread_mutex_lock( &mutex);
  // start of reading data from buffer
 
  copyData( &(fifo[ ptr ]), p) ;
  // end of reading data from buffer
  if( (++rPtr) >=  (FIFOSIZE * 2)) {
    rPtr = 0 ;
  }
  pthread_mutex_unlock( &mutex);
  printf("pop %d %d\n", ptr, (int)*p ) ;
}

void * thread1( void* pParam) {
  int i, j, d, randn ;
 
  for( i = 0 ; i < 1000 ; i++ ) {
    while( isFull()) {
        usleep( (rand() % 100)) ;
    }
    usleep( (rand() % 100)) ;
    push( (DATA *) &i ) ;
  }
}
void * thread2( void* pParam) {
  int i, j, d, randn ;
  for( j = 0 ; j < 1000 ; j++ ) {
    while( isEmpty()) {
        usleep( rand() % 100) ;
    }
    usleep( (rand() % 100)) ;
    pop( (DATA *) &d ) ;
  }
}


int main(void) {
  pthread_t tid1, tid2;
  pthread_create(&tid1, NULL, thread1, NULL);
  pthread_create(&tid2, NULL, thread2, NULL);

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

  return 0 ;
}

 

 



コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://diesaliquanti.blog.fc2.com/tb.php/606-1a338b12
この記事にトラックバックする(FC2ブログユーザー)

FC2Ad

まとめ

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。