12

flock(2)はスレッド セーフであるという印象を受けました。最近、複数のスレッドが同じファイルのロックを取得できるコードのケースに出くわしました。 c api 群れ。プロセス 25554 は、20 個のスレッドを持つマルチスレッド アプリであり、デッドロックが発生すると、同じファイルにロックされているスレッドの数が異なります。マルチスレッド アプリのtestEventはファイルへのライターであり、プッシュはファイルからのリーダーです。残念ながら、lsofLWP の値が表示されないため、ロックを保持しているスレッドを特定できません。以下の条件が発生すると、プロセスとスレッドの両方が群れの呼び出しで停止しますpstackstracepid 25569 および 25554 を呼び出します。RHEL 4.x でこれを克服する方法についての提案。

私が更新したかったことの 1 つは、メッセージの tx レートが 2 mbps を超える場合に限り、flock は常に誤動作しないということです。その tx レートを下回ると、すべてがファイルになります。num_threads= 20、 = 1000バイトを一定に保ち、size_of_msg1秒あたりのメッセージ送信数を10メッセージから100メッセージに変更しました。これは20 * 1000 * 100 = 2 mbpsであり、メッセージ数を150に増やして群れの問題を引き起こします起こります。

flockfile c api についてのご意見をお聞かせください。

 sudo lsof filename.txt
    COMMAND       PID     USER     FD       TYPE     DEVICE     SIZE   NODE       NAME
    push         25569    root     11u       REG      253.4      1079   49266853   filename.txt
    testEvent    25554    root     27uW      REG      253.4      1079   49266853   filename.txt
    testEvent    25554    root     28uW      REG      253.4      1079   49266853   filename.txt
    testEvent    25554    root     29uW      REG      253.4      1079   49266853   filename.txt
    testEvent    25554    root     30uW      REG      253.4      1079   49266853   filename.txt

write_data_lib_funclib 関数を呼び出すマルチスレッド テスト プログラム。

void* sendMessage(void *arg)  {

int* numOfMessagesPerSecond = (int*) arg;
std::cout <<" Executing p thread id " << pthread_self() << std::endl;
 while(!terminateTest) {
   Record *er1 = Record::create();
   er1.setDate("some data");

   for(int i = 0 ; i <=*numOfMessagesPerSecond ; i++){
     ec = _write_data_lib_func(*er1);
     if( ec != SUCCESS) {
       std::cout << "write was not successful" << std::endl;

     }

   }
   delete er1;
   sleep(1);
 }

 return NULL;

上記のメソッドは、テストのメイン関数の pthreads で呼び出されます。

for (i=0; i<_numThreads ; ++i) {
  rc = pthread_create(&threads[i], NULL, sendMessage, (void *)&_num_msgs);
  assert(0 == rc);

}

ここにライター/リーダー ソースがあります。独自の理由により、単にカット アンド ペーストしたくありませんでした。ライター ソースは、プロセス内の複数のスレッドにアクセスします。

int write_data_lib_func(Record * rec) {      
if(fd == -1 ) {  
    fd = open(fn,O_RDWR| O_CREAT | O_APPEND, 0666);
} 
if ( fd >= 0 ) {
   /* some code */ 

   if( flock(fd, LOCK_EX) < 0 ) {
     print "some error message";
   }
   else { 
    if( maxfilesize) {
      off_t len = lseek ( fd,0,SEEK_END);
      ...
      ... 
      ftruncate( fd,0);
      ...
      lseek(fd,0,SEEK_SET); 
   } /* end of max spool size */ 
   if( writev(fd,rec) < 0 ) {
     print "some error message" ; 
   }

   if(flock(fd,LOCK_UN) < 0 ) {
   print some error message; 
   } 

リーダー側には、スレッドのないデーモン プロセスがあります。

int readData() {
    while(true) {
      if( fd == -1 ) {
         fd= open (filename,O_RDWR);
      }
      if( flock (fd, LOCK_EX) < 0 ) { 
        print "some error message"; 
        break; 
      } 
      if( n = read(fd,readBuf,readBufSize)) < 0 ) { 
        print "some error message" ;
        break;
      }  
      if( off < n ) { 
        if ( off <= 0 && n > 0 ) { 
          corrupt_file = true; 
        } 
        if ( lseek(fd, off-n, SEEK_CUR) < 0 ) { 
          print "some error message"; 
        } 
        if( corrupt_spool ) {  
          if (ftruncate(fd,0) < 0 ) { 
             print "some error message";
             break;
           }  
        }
      }
      if( flock(fd, LOCK_UN) < 0 ) 
       print some error message ;
      }  
   }     
}
4

2 に答える 2

10

flock(2)は、「互換性のないロックが別のプロセスによって保持されている場合のブロック」および「flock()によって作成されたロックが開いているファイルテーブルエントリに関連付けられている場合のブロック」として文書化されているためflock、複数のスレッドによる-edロックが期待されます。同じプロセスの相互作用しません。(flockドキュメントにはスレッドについては記載されていません)。

したがって、解決策は単純である必要があります。1つpthread_mutex_tをすべての可能なflockファイル記述子に関連付け、への呼び出しをflockそのミューテックスで保護します。読み取りロックと書き込みロックが必要な場合は、pthread_rwlock_tを使用することもできます。

于 2012-02-27T09:26:52.973 に答える
3

flock(2)のLinuxのマニュアルページから:

flock()によって作成されたロックは、開いているファイルテーブルエントリに関連付けられています。これは、重複するファイル記述子(たとえば、fork(2)またはdup(2)によって作成される)が同じロックを参照し、このロックはこれらの記述子のいずれかを使用して変更または解放できることを意味します。さらに、これらの重複する記述子のいずれかに対する明示的なLOCK_UN操作によって、またはそのようなすべての記述子が閉じられたときに、ロックが解放されます。

さらに、flockロックは「スタック」しないため、すでに保持しているロックを取得しようとすると、flock呼び出しは、ブロックせずに、またロック状態を変更せずにすぐに戻るnoopです。

プロセス内のスレッドはファイル記述子を共有するため、異なるスレッドからファイルを複数回フロックすることができ、ロックはすでに保持されているため、ブロックされません。

また、flock(2)に関する注記から:

flock()ロックとfcntl(2)ロックは、フォークされたプロセスとdup(2)に関して異なるセマンティクスを持っています。fcntl(2)を使用してflock()を実装するシステムでは、flock()のセマンティクスはこのマニュアルページで説明されているものとは異なります。

于 2012-02-28T06:14:00.727 に答える