JavaScriptでミューテックスは必要ですか?


104

私はこのリンクを見ました:JavaScriptでの相互排除の実装。一方、JavaScriptにはスレッドがないことを読みましたが、それはどういう意味ですか?

イベントが発生したとき、コードのどこで中断できますか?

JSにスレッドがない場合、JSでミューテックスを使用する必要がありますか?

具体的には、私はによって呼び出される関数使用した場合の効果について疑問に思ってsetTimeout()XmlHttpRequestさんをonreadystatechangeグローバルにアクセス変数に。


1
いいえ、JavaScriptのミューテックスやその他の同時実行制御ツールはありません。JavaScriptで同時実行制御ツールがない理由をご覧ください。
Uzair Farooq 2015

回答:


101

Javascriptは再入可能な言語として定義されています。つまり、ユーザーに公開されるスレッドはなく、実装にスレッドがある可能性があります。setTimeout()非同期コールバックなどの関数は、実行する前にスクリプトエンジンがスリープするのを待つ必要があります。

つまり、イベントで発生するすべてのことは、次のイベントが処理される前に終了する必要があります。

つまり、非同期イベントが発生したときとコールバックが呼び出されたときの間に値が変化しないことを期待するコードを実行する場合は、ミューテックスが必要になることがあります。

たとえば、1つのボタンをクリックして、コールバックを呼び出すXmlHttpRequestを送信するデータ構造があり、破壊的な方法でデータ構造を変更し、イベントが発生したときに同じデータ構造を直接変更する別のボタンがある場合発生し、コールバックが実行されると、ユーザーはコールバックの前にデータ構造をクリックして更新し、値を失う可能性があります。

このような競合状態を作成することはできますが、各関数はアトミックであるため、コードでそれを防ぐのは非常に簡単です。それは多くの作業であり、実際には競合状態を作成するためにいくつかの奇妙なコーディングパターンを取るでしょう。


13
この競合状態を作成することはまったく難しくありません。たとえば、フィールドに「onkeyup」イベントがあり、DBへのajax呼び出しをトリガーしていくつかの値を取得します。データをすばやく入力すると、簡単に順序が狂う結果になる可能性があります。
thomasb 2017年

19

この質問への回答は少し古くなっていますが、与えられた時点では正解です。また、Webワーカーを使用しないクライアント側のJavaScriptアプリケーションを見ると、問題は解決します。

Webワーカーに関する記事:WebワーカーのMozillaを
使用したJavaScriptでのマルチスレッド

これは、Webワーカーを介したJavaScriptにマルチスレッド機能があることを明確に示しています。質問に関しては、JavaScriptでミューテックスが必要ですか?私にはこれがよくわかりません。しかし、このstackoverflowの投稿は関連があるようです:
N個の非同期スレッドの相互排除


3
過去からの爆風だが、複数のタブが同じローカルストレージにアクセスするときにミューテックスが必要になった
psp

3
WebWorkersは変数の状態を共有せず、イベントをトリガーするメッセージを渡すことによってのみメインスレッドと通信するため、再入可能性に影響を与えません。
Alnitak 2014

9

@williamが指摘するように、

非同期イベントが発生したときとコールバックが呼び出されたときの間に値が変化しないことを期待するコードを実行する場合は、ミューテックスが必要になることがあります。

これはさらに一般化することができます。非同期リクエストが解決されるまで、リソースの排他制御を期待するコードを実行する場合は、ミューテックスが必要になる場合があります。

簡単な例は、バックエンドにレコードを作成するためにajax呼び出しを起動するボタンがある場合です。幸せなユーザーが離れてトリガーして複数のレコードが作成されるのを防ぐために、少しのコードが必要になる場合があります。この問題にはいくつかのアプローチがあります(ボタンを無効にする、ajaxの成功時に有効にするなど)。単純なロックを使用することもできます。

var save_lock = false;
$('#save_button').click(function(){
    if(!save_lock){
        //lock
        save_lock=true;
        $.ajax({
            success:function()
                //unlock
                save_lock = false;  
            }
        });
    }
}

それが最善のアプローチであるかどうかはわかりませんが、他の人がJavaScriptで相互排除をどのように処理するのか興味がありますが、私が知る限り、これは単純なミューテックスであり、便利です。


4
単一のブロックのコンテキストで2つのスレッドが実行されていないため、少なくとも従来の意味では、これをミューテックスと呼ぶことはほとんどありません。
Ovesh 2011

10
ミューテックスは、「共通リソースの同時使用を回避する」のに役立つ単純なアルゴリズムです。マルチスレッド化はミューテックスの必要性を生み出しますが、ミューテックスはあなたが説明する状況に固有であると言う定義には何もありません。
alzclarke

1
あなたはミューテックスの正式な定義について正しいです。しかし、現実の世界でミューテックスについて話すとき、これはほとんど考えられません。
Ovesh

これは期待どおりに機能していません。残念ながら、繰り返しクリックすると、ajax呼び出しが発生します。他のアイデアは?
Mohammed Shareef C

1
これは、再試行とタイムアウトのロジックを使用できるように、n回の失敗後にwhilewith setTimeoutまたはa setIntervalでラップする必要がありclearIntervalます。そのままにすることは、ロックされているコードをバイパスすることを意味します。mutexと共有オブジェクトを使用した外部処理は、実装自体と同じくらい重要です。
MrMesees

6

JavaScriptはシングルスレッドです... Chromeは新しいビーストかもしれませんが(それもシングルスレッドだと思いますが、各タブには独自のJavaScriptスレッドがあります...詳細に調べていないので、引用しないでください)そこ)。

ただし、心配する必要があることの1つは、JavaScriptが複数のajaxリクエストを、送信する順序とは異なる順序で処理する方法です。したがって、本当に心配する必要があるのは、結果が送信した順序とは異なる順序で戻ってきた場合に、お互いの足元を踏まないようにajax呼び出しが処理されることを確認することだけです。

これはタイムアウトにも当てはまります...

JavaScriptがマルチスレッド化すると、ミューテックスなどが心配になるかもしれません。


4

はい、localStorageのようにタブ/ウィンドウ間で共有されているリソースにアクセスする場合、JavaScriptでミューテックスが必要になる場合があります

たとえば、ユーザーが2つのタブを開いている場合、次のような単純なコードは安全ではありません。

function appendToList(item) {
    var list = localStorage["myKey"];
    if (list) {
        list += "," + item;
    }
    else {
        list = item;
    }
    localStorage["myKey"] = list;
}

localStorageアイテムが「取得」されてから「設定」されるまでの間に、別のタブが値を変更した可能性があります。それは一般的にはありそうもないことですが、可能です-特定の状況での競合に関連する可能性とリスクを自分で判断する必要があります。

詳細については、次の記事を参照してください。


2

JavaScript(言語)は必要に応じてマルチスレッド化できますが、JavaScriptエンジンのブラウザー埋め込みは一度に(おそらくタブごとに)1つのコールバック(onload、onfocus、<script>など...)のみを実行します。コールバックの登録と受信の間の変更にミューテックスを使用するというウィリアムの提案は、ロック解除するコールバックが現在のコールバックの背後でブロックされるため、介在するコールバックでブロックしたくないので、文字どおりに解釈しないでください。 !(まあ、英語はスレッドについて話すのが面倒です。)この場合、フラグが設定されている場合、現在のイベントの再ディスパッチの行に沿って、文字通りまたはsetTimeout()のような方法で何かをしたいと思うでしょう。

JSの別の埋め込みを使用していて、一度に複数のスレッドを実行する場合、少し厄介なことがありますが、JSがコールバックを簡単に使用でき、プロパティアクセスのオブジェクトをロックするため、明示的なロックはほとんど必要ありません。ただし、マルチスレッドを使用する一般的なコード(ゲームスクリプトなど)用に設計された埋め込みが、いくつかの明示的なロックプリミティブも提供しなかった場合は、驚きます。

テキストの壁でごめんなさい!


0

イベントは通知されますが、JavaScriptの実行は依然としてシングルスレッドです。

私の理解では、イベントが通知されると、エンジンはイベントハンドラーを実行するために現時点で実行しているものを停止します。ハンドラが終了すると、スクリプトの実行が再開されます。イベントハンドラーが一部の共有変数を変更した場合、再開されたコードでは、これらの変更が「突然」表示されます。

共有データを「保護」したい場合は、単純なブールフラグで十分です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.