5

この質問は、制限付きの技術的な使用法ではなく、主観的な使用法に関するものです。技術的に制限がどのように機能するかについては誤解されているかもしれませんが、その場合は、誤った前提に基づいて質問をするために私をグリルしてください。

これまでのところ、restrictedを使用している2つの例を次に示します。

不変の文字のシーケンスへのポインターを受け取る関数がある場合、他の人が関数の実行と同時に、たとえば別の並列から、自分のポインターを介してデータにアクセスできるため、制限されているとは言えません。スレッド。データは変更されていないので、問題ありません。

ただし、関数が変更する可能性のある一連の可変文字へのポインターを取得する場合、潜在的に一貫性のないデータによる関数。また、データが変更される可能性も記載されているため、コーダーは古いデータを読み取らないこと、およびアクセスするときなどにメモリバリアを使用する必要があることを認識しています...

私はあまりCをコーディングしていないので、ここで想定していることについて簡単に間違っている可能性があります。これはrestrictの正しい使用法ですか?このシナリオで行う価値はありますか?

また、関数が戻ったときに制限付きポインターがスタックからポップされると、他のポインターを介してデータに自由にアクセスできるようになり、制限は制限付きポインターの間だけ続くと想定しています。「非公式」ポインターを介して制限されたデータにアクセスするのはUBであるため、これはルールに従ったコーダーに依存していることを私は知っています。

私はこれをすべて正しく理解しましたか?

編集:

ユーザーが複数のスレッドを介してデータにアクセスするのを妨げることはまったくないことをすでに知っていることを明確にしておきたいと思います。また、C89には「スレッド」が何であるかさえ知らないことも知っています。

ただし、参照を介して引数を変更できるコンテキストを考えると、関数の実行中に引数にアクセスしてはならないことは明らかです。これはスレッドセーフを強制するために何もしませんが、あなた自身のリスクで関数の実行中にあなた自身のポインタを介してデータを変更することを明確に文書化します。

スレッド化が完全に方程式から外されたとしても、それが私にとって正しいと思われるシナリオでは、さらに最適化することができます。

それでも、これまでのすべての信頼できる回答に感謝します。気に入ったすべての回答に賛成しますか、それとも受け入れた回答だけに賛成しますか?複数が受け入れられた場合はどうなりますか?申し訳ありませんが、私はここで新しいです、私は今FAQをより徹底的に調べます...

4

4 に答える 4

5

restrictスレッドセーフとは何の関係もありません。実際、既存のC標準は、スレッドのトピックについては何も言うことはありません。スペックの観点からは、「スレッド」のようなものはありません。

restrictエイリアシングについてコンパイラに通知する方法です。コンパイラは、コンパイル時に2つのポインタが実際に同じメモリを参照しているかどうかを知ることができないため、ポインタによってコンパイラが効率的なコードを生成するのが困難になることがよくあります。おもちゃの例:

void foo(int *x, int *y) {
    *x = 5;
    *y = 7;
    printf("%d\n", *x);
}

コンパイラがこの関数を処理するとき、同じメモリ位置xを参照しているかどうかはわかりません。したがって、印刷するか、をy出力するかはわかりません。また、を呼び出す前に実際に読み取るコードを出力する必要があります。57*xprintf

xただし、として宣言するとint *restrict x、コンパイラはこの関数が出力することを証明できる5ため、コンパイル時定数をprintf呼び出しにフィードできます。

このような最適化の多くはrestrict、特に配列の操作について話しているときに、で可能になります。

しかし、これはスレッドとは何の関係もありません。マルチトレッドアプリケーションを正しく使用するには、ミューテックス、条件変数、メモリバリアなどの適切な同期プリミティブが必要です。これらはすべてプラットフォームに固有であり、とは関係ありませんrestrict

[編集]

ドキュメントの形式として使用することについてのあなたの質問に答えるためにrestrict、私はそれにも「いいえ」と言います。

変数に同時にアクセスできる場合とできない場合を文書化する必要があると考えているようです。ただし、共有データの場合、適切な規律は(ほとんどの場合)同時にアクセスされないようにすることです。

変数に関連するドキュメントは、それが共有されているかどうか、およびどのミューテックスがそれを保護しているかです。何らかの理由でその変数にアクセスするコードは、それを読み取るためであっても、ミューテックスを保持する必要があります。作成者は、他のスレッドが変数に同時にアクセスするかどうかを知り、気にする必要はありません...他のスレッドは同じ規律に従い、mutexは同時アクセスがないことを保証するためです。

この規律は単純で、機能し、拡張性があります。そのため、スレッド間でデータを共有するための主要なパラダイムの1つです。(もう1つはメッセージパッシングです。)「今回は本当にミューテックスをロックする必要があるのか​​」と考えようとしていることに気付いた場合は、ほぼ間違いなく何か間違ったことをしていることになります。この点を誇張するのは難しいでしょう。

于 2011-07-16T16:55:43.253 に答える
3

いいえ、これはさまざまなスレッドからのアクセスに関する情報を提供するのに適した方言ではないと思います。これは、特定のコードの平和が、それが処理するさまざまなポインターに対して取得するポインターに関するアサーションとして意図されています。スレッド化はまだ言語の一部ではありません。データへのスレッドセーフなアクセスにはさらに多くのニーズrestrictがあり、適切なツールではありません。volatile保証ではありませんが、提案されていることもあります。

  • ミューテックスまたはその他のロック構造
  • データの整合性を保証するメモリフェンス
  • 不可分操作と型

今後の標準C1xは、そのような構成を提供することになっています。C99はそうではありません。

于 2011-07-16T16:55:49.083 に答える
1

の標準的な例はrestrictmemcpy()のとおりです。OSX10.6のマンページでは、プロトタイプを次のように示しています。

void* memcpy(void *restrict s1, const void *restrict s2, size_t n);

の送信元リージョンと宛先リージョンmemcpyをオーバーラップさせることはできません。restrictしたがって、この制限が適用されていることを示すラベルを付けることで、コンパイラは、ソース配列のどの部分も宛先とエイリアスしていないことを知ることができます。ソースの大きなチャンクを読み取ってから宛先に書き込むなどのことができますか?

基本的restrictには、ポインタをエイリアシングではないものとしてタグ付けすることでコンパイラの最適化を支援することです。それ自体はスレッドセーフには役立ちません。関数の呼び出し中に、ポイントされたオブジェクトが自動的にロックされることはありません。

より長い議論については、Cで修飾された制限の使用方法と制限に関するウィキペディアの記事を参照してください

于 2011-07-16T16:46:11.480 に答える
1

restrictは、ポインターを介してアクセスされるバッファーが、スコープ内の別のポインターを介してエイリアス化されていないことをコンパイラーに示すヒントです。したがって、次のような関数がある場合:

foo(char *restrict datai, char *restrict dataj)
{
    // we've "promised" the compiler that it should not worry about overlap between 
    // datai and dataj buffers, this gives the compiler the opportunity to generate 
    // "better" code, potentially mitigating load-store issues, amongst other things
}

restrictただし、マルチスレッドアプリケーションで保護されたアクセスを提供するには、使用しないだけでは不十分です。読み取り/書き込み方法でパラメーターを介して複数のスレッドによって同時にアクセスされる共有バッファーがある場合、char *何らかのロック/ミューテックスなどを使用する必要がある可能性があります-存在restrictしないことはスレッドセーフを意味しません。

お役に立てれば。

于 2011-07-16T16:56:43.423 に答える