web-dev-qa-db-ja.com

javascriptにはmutexが必要ですか?

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

イベントが発生すると、コードのどこで割り込みが可能ですか?

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

具体的には、グローバルにアクセス可能な変数でsetTimeout()およびXmlHttpRequestonreadystatechangeによって呼び出される関数を使用した場合の効果について疑問に思っています。

99
Ovesh

Javascriptは 再入可能 ユーザーに公開されるスレッドが存在しないことを意味する言語。実装にスレッドが存在する場合があります。 setTimeout()などの関数や非同期コールバックは、スクリプトエンジンがスリープ状態になるのを待ってから実行する必要があります。

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

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

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

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

95
William

この質問への答えは少し古くなっていますが、与えられた時点では正しいです。また、Webworkerを使用しないクライアント側のjavascriptアプリケーションを見る場合でも正しいです。

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

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

18
gorillatron

@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で相互排除をどのように処理するのか興味がありますが、私が知る限り、それは単純なミューテックスであり、便利です。

9
alzclarke

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

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

これもタイムアウトになります...

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

5
Mike Stone

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

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

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

LocalStorageアイテムが 'got'と 'set'の間に、別のタブが値を変更した可能性があります。一般的に考えられないことですが、可能です-特定の状況での競合に関連する可能性とリスクを自分で判断する必要があります。

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

3
decates

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

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

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

1
Constantin

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

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

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

1
Simon Buchan