11

次の簡単な C プログラムを考えてみましょう。

#include <errno.h>
int
main(int argc, char* argv[]) {
  return errno;
}

Solaris でコンパイルした場合、このコードの動作は の存在に依存し-D_REENTRANTます。

solaris$ cc -E test.c | grep return
  return errno;
solaris$ cc -D_REENTRANT -E test.c | grep return
  return  ( * ( ___errno ( ) ) );

後者のバージョンはスレッドセーフです。Linux で同じコードをコンパイルすると、同じ動作が得られます。-D_REENTRANT

linux$ gcc -E test.c | grep return
  return (*__errno_location ());
linux$ gcc -D_REENTRANT -E test.c | grep return
  return (*__errno_location ());

Solaris'ccにはオプションがあり、これは'sと同様-mtに を意味します。ただし、ライブラリの場合、これらのマルチスレッド オプションを指定すると、スレッド ランタイムに不要な依存関係が挿入されるため、不十分に思えます。ただし、ライブラリをスレッドセーフ (errno を含む) にする必要がある場合は、ライブラリのコンパイル時と派生コードの両方でスレッドセーフなセマンティクスが必要です。Linux では、errno は常にスレッド ローカルであるため、これは簡単ですが、上記で示したように、他のシステムでは保証されません。-D_REENTRANTgcc-pthread

その結果、スレッド セーフなライブラリを適切にコンパイルし、ヘッダーを付けて配布するにはどうすればよいかという疑問が生じます。1 つのオプションは#define _REENTRANT、メイン ヘッダー内にあることですが、これが#include <errno.h>ライブラリ ヘッダーのインクルードの前に発生すると、問題が発生します。別のオプションは、ライブラリを でコンパイルし、が定義されていない場合は-D_REENTRANTメイン ヘッダーを持つことです。#error_REENTRANT

スレッドセーフなライブラリを作成し、リンクされているコードと正しく相互運用できるようにするための正しい/最良の方法は何ですか?

4

2 に答える 2

4

現在、Solaris マシンにアクセスできないため、これをテストすることはできません。しかし、 (を含める前に) の#define _POSIX_C_SOURCE 200112L一番最初の行として入れるとどうなるでしょうか? Solaris が POSIX に準拠している場合は、スレッドセーフ バージョンに展開する必要があります。これは、POSIX で次のように定義されているためです。test.c<errno.h>errnoerrno

プロセスのスレッドごとに、errnoの値は、他のスレッドによる関数呼び出しまたはerrnoへの代入の影響を受けません。

したがって、これは任意の POSIX 準拠システムに移植できます。実際、POSIX 準拠のアプリケーション コードを記述したい場合は、対象とする POSIX の最小バージョンに適した値を常に定義する必要があります。_POSIX_C_SOURCE定義は、ヘッダーを含める前に、すべてのソース ファイルの先頭にある必要があります。標準の2001年版から:

厳密に準拠した POSIX アプリケーションは、IEEE Std 1003.1-2001 で説明されている機能のみを必要とするアプリケーションです。そのようなアプリケーション:

...

8. C プログラミング言語の場合、ヘッダーが含まれる前に _POSIX_C_SOURCE を 200112L に定義する必要があります。

于 2013-04-11T10:58:21.450 に答える
0

ライブラリが autoconf を使用している場合、おそらくAC_USE_SYSTEM_EXTENSIONSマクロを使用する必要があります。このマクロは、POSIX +extensions セマンティクスを有効にするターゲット固有の定義を設定します。現時点でテストする Solaris システムはありませんが、_POSIX_PTHREAD_SEMANTICS でスレッドセーフな errno を有効にする必要があると思います。少なくとも、Solaris が面倒なことにデフォルトで提供している POSIX ドラフトの _r() バリアントではなく、POSIX _r() 関数を有効にします。

于 2014-10-13T04:49:38.800 に答える