1

C、pthreads、およびソケットを使用して Linux でアプリケーションを作成しています。

これはクライアント/サーバー アプリケーションで、サーバーには N+2 スレッドがあり、N - アクティブなクライアントの数で、1 つのスレッドは新しい接続を受け入れてクライアントのスレッドを作成し、最後の 1 つはユーザー入力を受け入れます。

リンクされたリストを使用して、アプリケーションに関連するいくつかのデータを保存します。すべてのクライアントがリスト内の 1 つのノードに関連付けられます。これらのクライアント スレッドは、ノードに保存されている情報を、1 秒、2 分などの間隔で更新し、動的に変化します。

ここに問題があります。ユーザーが要求した場合、リンクされたリストに格納されている情報を標準出力に書き込む必要があります。もちろん、書き込み中にミューテックスを取得する必要があります。リスト全体に対して1つのミューテックスがパフォーマンスを妨げるのではないかと心配しています。

すべてのノードにミューテックスを関連付けることを考えていましたが、指定されたノードの削除が複雑になります (まず、「stdout ライター」スレッドがリストをトラバースしないようにする必要があり、ミューテックスも取得する必要があります)。私のノードと前のノードの次のノードを指すポインターを変更するなど-前のノードまでずっとトラバースする必要があるか、二重リンクリストを作成する必要があります)。

したがって、複数のミューテックスを含むソリューションが、はるかに複雑なコード、条件、およびこのすべてのロック、待機、およびロック解除でさらに優れているかどうか疑問に思っています。

4

4 に答える 4

3

ノードごとのミューテックスを使用すると、コードがより複雑になることは間違いありません。これは、値を決定する必要があるトレードオフです。ロックの競合が発生する可能性がありますが、コードはロックの存在による影響をほとんど受けないため、記述が容易になります。または、競合の可能性を大幅に減らしてより多くのロックを設定することもできます。パフォーマンスは向上しますが、コードの記述と修正が難しくなります。ノードのグループごとにロックを設定することで、中間に何かを設定することもできます。いくつかのノードをまとめて割り当て、そのグループにロックを設定します。ただし、フリー リストの追跡に問題が発生し、断片化の可能性が生じます。

追加操作、削除操作、完全なリストの反復、およびその他 (再編成、検索、その他アプリケーションで必要となるもの) の相対的な頻度を考慮する必要があります。追加/削除が非常に頻繁であるが、リストをたどることが 3 回目のブルームーンに 1 回である場合は、単一のロックが適切である可能性があります。しかし、リストをたどる (データの完全なダンプ、または検索など) ことが非常に一般的である場合は、より詳細なアプローチがより魅力的になります。ミューテックスの代わりにリーダー/ライター ロックを検討する必要さえあるかもしれません。

于 2012-06-08T18:29:12.177 に答える
1

数万または数十万のユーザーがいない限り、リストを読むのにそれほど時間はかかりません。ローカルの中間リストを作成して、書き込み中に元のリストがロックされないようにすることができます。これには時間かかる場合があります。これは、ある時点でリストのスナップショットを取得することも意味します。個々のノードをロックする場合は、Aを削除してから、要素Bを削除しても、Bが表示されない場合でも、表示されるリストにAを表示させることができます。

私が理解しているように、個々のノードをロックしたい場合は、リストを単独でリンクする必要があります。追加と削除はかなり注意が必要です。Javaには、高速のコンペアアンドスワップ技術を使用してこれを行ういくつかのシステムクラスがあります。Cにはそのようなコードが必要ですが、どこで探すべきかわかりません。そして、あなたはそれらの時系列的に挑戦された結果を得るでしょう。

于 2012-06-08T18:51:40.123 に答える
1

リストを最後までトラバースする必要はありません。リストをトラバースしながら、次の要素が削除したい要素かどうかをテストし、両方のノードをロックすることができます - コード全体で常に同じ順序で、デッドロックを回避します。また、ダブル チェック イディオムを使用して、ミューテックス ノードをロックすることもできます。

remove
    for node in list
        if node->next is the desired node
            lock(node)
            lock(node->next)
                if node->next is the desired node
                    do removing stuff
                else
                    treat concurrent modification - retry, maybe?
            release(node->next)
            release(node)

このイディオムを使用すると、読み取り中にリスト全体をロックする必要がなくなり、最初のテストとロックの間に実行された変更もチェックされます。ミューテックスの配列を使用すると、コードがそれほど複雑になるとは思いません。ロックのオーバーヘッドは、IO などの操作と比較して何もありません。

于 2012-06-08T18:35:40.203 に答える
0

N個のアクティブなクライアントにN個のスレッドを使用する場合は、pthread_setspecificとpthread_getspecificを使用するオプションを検討してください。

于 2012-06-08T18:04:32.593 に答える