排他をさらに

考え直してみたら、一度tryrdlock(&rw)とtrylock(&m)に失敗したスレッドではもうtrylock(&m)を試す必要がなかった。つまり

void read() {
  int rdlockerr = tryrdlock(&rw);
  if (rdlockerr && trylock(&m)) {
    rdlockerr = rdlock(&rw);
    if (rdlockerr) {
      //エラーなので適当に処理
    }
  }
  //排他でのread作業
  //上のエラーの場合は考慮していない
  if (rdlockerr) {
    unlock(&m);
  } else {
    unlock(&rw);
  }
}

というコードで充分だ。少しはすっきりしたけどもまだあまり整ってはいない。やはりscoped_lockにした方が良いかなぁ。

      • -

pthreadのドキュメントを読み直したらEDEADLKというのがあった。これを使えば良かったらしい。というわけで正しいコードは

rwlock_t rw;
void write() {
  int ret = wrlock(&rw);
  if (ret) {
    //エラー処理
  }
  //排他でのwrite作業
  unlock(&rw);
}
void read() {
  int ret = rdlock(&rw);
  if (!(!ret || ret==EDEADLK)) {
    //エラー処理
  }
  //排他でのread作業
  if (ret!=EDEADLK) {
    unlock(&rw);
  }
}

となった(エラー処理も追加)。pthread初心者なのだからドキュメントはちゃんと読まないと。

      • -

いや、そうでもなかった。wrlock(&rw)しているスレッドがrdlock(&rw)した場合、必ずしもEDEADLKを返すわけでもないのか。正式な規格を読まないと判らないとしか。ううむ、MT対応に挫折しそうだ。
http://www.opengroup.org/onlinepubs/009695399/
を読めば良いのだろうか。

The pthread_rwlock_rdlock() function may fail if:

[EDEADLK]
A deadlock condition was detected or the current thread already owns the read-write lock for writing.

やはりmayか。