2

Linux で C ライブラリを作成しています。これにはいくつかの関数があり、いくつかのグローバル データを一緒に操作します。これらの関数をスレッド セーフにするためには、コード内の適切なポイントでミューテックスを使用する必要があります。

Linux では、アプリケーションで pthread を使用するには、適切なライブラリ-lpthreadにリンクする必要があります。私のライブラリがコンパイルされたら、そのライブラリのユーザーがアプリケーションで pthread を使用することを決定した場合と使用しない場合の両方で機能させたいと考えています。

開発者がアプリケーションでスレッドを使用しない場合、それらは pthread に対してリンクしません。したがって、コンパイルされたライブラリでそれを必要としないようにしたいと思います。さらに、単一のスレッド化されたアプリケーションでミューテックスを使用すると、不必要なオーバーヘッドが使用されます (言うまでもなくばかげています)。

特定のシンボルがリンクされている場合にのみ特定のコードブロックが実行されるコードを (必要に応じて GCC 拡張を使用して) 記述する方法はありますか? dlopen()とその仲間を使用できることは承知していますが、それ自体で回避しようとしていることがいくつか必要になります。いくつかの標準関数が同じボートにあり、ミューテックスをスレッドセーフにする必要があるため (そしてそれらはそうです)、pthreads とリンクされていなくても機能するため、私が探しているものが存在する必要があると思います。

この時点で、66 行目と 67 行目の FreeBSD の popen() 関数が移植性のないチェック ( isthreaded ) を使用して、スレッドが使用されているかどうか、およびミューテックスを使用するかどうかを判断していることに気付きました。そのようなものが何らかの方法で標準化されているとは思えません。しかし、シンボルが認識されない場合、そのようなコードはコンパイルおよびリンクできません。Linux では、pthread がリンクされていない場合、mutex シンボルは存在しません。

要約すると、Linux では、アプリケーション開発者が特にどこかでスレッドを使用したい場合を除き、スレッドがいつ使用されるかを認識し、必要に応じてミューテックスを使用し、pthread に対するリンクを必要としないライブラリを作成するにはどうすればよいでしょうか?

4

2 に答える 2

3

いくつかのテストの後、Linux はすでに私が望んでいることを自動的に行っているようです! pthread ミューテックスのサポートだけが必要な場合ではなく、スレッド化を使用する場合にのみ pthread に対してリンクする必要があります。

このテスト ケースでは:

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

int main()
{
  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

  if (!(errno = pthread_mutex_lock(&mutex))) { puts("Mutex locked!"); }
  else { perror("Could not lock mutex"); }

  if (!(errno = pthread_mutex_lock(&mutex))) { puts("Mutex locked!"); }
  else { perror("Could not lock mutex"); }

  return 0;
}

pthread をリンクせずにこれをコンパイルすると、「Mutex locked!」と表示されます。二回。これは、 pthread_mutex_lock() が本質的に非操作であることを示しています。ただし、pthreads がリンクされている場合、このアプリケーションを実行すると、最初の "Mutex locked!" の後に停止します。印刷されます。

したがって、必要に応じてライブラリでミューテックスを使用でき、pthreads を使用する必要がなく、不要な場合は (かなりの?) オーバーヘッドがありません。

于 2013-10-12T23:22:05.933 に答える
0

通常の解決策は次のとおりです。

  1. スイッチを使用#defineしてビルド時に pthreads 関数を呼び出すかどうかを制御し、ビルド プロセスでライブラリの 2 つのバージョンを作成します。ライブラリのユーザーに依存して、正しいライブラリにリンクしてください。

  2. pthreads 関数を直接呼び出さないでください。代わりに、ユーザー提供のコールバックlockunlockコールバックを呼び出します (必要な場合は、thread-local-storage も)。ライブラリ ユーザーは、適切なロック メカニズムを割り当てて呼び出す責任があります。これにより、pthreads 以外のスレッド ライブラリを使用することもできます。

  3. 何もせず、ライブラリ関数が複数のスレッドから同時に入力されないようにする必要があることをユーザー コードで文書化するだけです。

glibc はまた別のことを行います - バイナリにリンクされている場合にのみ、遅延バインディング シンボルを使用したトリックを使用して、pthreads 関数を呼び出します。ただし、pthreads の glibc 実装の特定の詳細に依存しているため、これは移植可能ではありません。の定義を__libc_maybe_call()参照してください。

#ifdef __PIC__
# define __libc_maybe_call(FUNC, ARGS, ELSE) \
  (__extension__ ({ __typeof (FUNC) *_fn = (FUNC); \
                    _fn != NULL ? (*_fn) ARGS : ELSE; }))
#else
# define __libc_maybe_call(FUNC, ARGS, ELSE) \
  (FUNC != NULL ? FUNC ARGS : ELSE)
#endif
于 2013-10-12T23:25:27.207 に答える