자바 스크립트에 뮤텍스가 필요합니까?


104

나는이 링크를 보았다 : Implementing Mutual Exclusion in JavaScript . 다른 한편으로, 나는 자바 스크립트에 스레드가 없다는 것을 읽었지만 정확히 무엇을 의미합니까?

이벤트가 발생하면 코드에서 인터럽트 할 수있는 곳은 어디입니까?

그리고 JS에 스레드가 없으면 JS에서 뮤텍스를 사용해야합니까?

특히, 전역 적으로 액세스 할 수있는 변수에 대한 setTimeout()XmlHttpRequest's onreadystatechange에 의해 호출되는 함수를 사용하는 효과에 대해 궁금 합니다.


1
아니, 뮤텍스 또는 자바 스크립트의 다른 동시성 제어 도구가 없습니다. javascript에 동시성 제어 도구가없는 이유를 참조하십시오 .
Uzair Farooq

답변:


101

자바 스크립트는 재진입 언어로 정의되어 사용자에게 노출되는 스레딩이 없으며 구현에 스레드가있을 수 있습니다. setTimeout()및 비동기 콜백 과 같은 함수 는 스크립트 엔진이 실행되기 전에 휴면 상태가 될 때까지 기다려야합니다.

즉, 이벤트에서 발생하는 모든 작업은 다음 이벤트가 처리되기 전에 완료되어야합니다.

즉, 코드가 비동기 이벤트가 시작된 시점과 콜백이 호출 된 시점 사이에 값이 변경되지 않을 것으로 예상하는 작업을 수행하는 경우 뮤텍스가 필요할 수 있습니다.

예를 들어 버튼 하나를 클릭하고 콜백을 호출하는 XmlHttpRequest를 전송하는 데이터 구조가있는 경우, 데이터 구조를 파괴적인 방식으로 변경하고 이벤트가 발생했을 때 동일한 데이터 구조를 직접 변경하는 다른 버튼이있는 경우 호출되고 콜백이 실행되었을 때 사용자는 콜백 전에 데이터 구조를 클릭하고 업데이트하여 값을 잃을 수 있습니다.

이와 같은 경쟁 조건을 만들 수 있지만 각 함수는 원자 적이므로 코드에서이를 방지하는 것은 매우 쉽습니다. 실제로 경쟁 조건을 생성하려면 많은 작업이 필요하고 이상한 코딩 패턴이 필요합니다.


13
이 경쟁 조건을 생성하는 것은 전혀 어렵지 않습니다. 예를 들어, 필드에 "onkeyup"이벤트가있어서 일부 값을 얻기 위해 DB에 대한 ajax 호출을 트리거합니다. 데이터를 빠르게 입력하면 순서가 잘못된 결과를 쉽게 얻을 수 있습니다.
thomasb

19

이 질문에 대한 답변은 제공된 당시에는 정확하지만 약간 구식입니다. 웹 워커를 사용하지 않는 클라이언트 측 자바 스크립트 애플리케이션을 보면 여전히 정확합니다.

웹 워커에 대한 기사 : 웹 워커를
사용하는 자바 스크립트에서 멀티 스레딩워커의
Mozilla

이것은 웹 작업자를 통한 자바 스크립트가 다중 스레딩 기능을 가지고 있음을 분명히 보여줍니다. 질문에 관해서는 자바 스크립트에 뮤텍스가 필요합니까? 잘 모르겠습니다. 그러나이 stackoverflow 게시물은 관련성이있는 것 같습니다.
N 비동기 스레드에 대한 상호 배제


3
과거에서 폭발했지만 여러 탭이 동일한 로컬 저장소에 액세스 할 때 뮤텍스가 필요하다는 것을
psp

3
WebWorker는 변수 상태를 공유하지 않고 이벤트를 트리거하는 메시지를 전달하여 주 스레드와 만 통신하기 때문에 재진입에 영향을주지 않습니다.
Alnitak

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;  
            }
        });
    }
}

이것이 최선의 접근 방식인지 확실하지 않으며 다른 사람들이 자바 스크립트에서 상호 배제를 처리하는 방법에 관심이 있지만 내가 아는 한 그것은 단순한 뮤텍스이며 편리합니다.


4
적어도 전통적인 의미에서는 이것을 뮤텍스라고 부르지 않을 것입니다. 왜냐하면 당신은 항상 단일 블록의 맥락에서 실행되는 두 개의 스레드를 가지고 있지 않기 때문입니다.
Ovesh 2011

10
뮤텍스는 '공통 자원의 동시 사용을 방지'하는 데 도움이되는 단순한 알고리즘입니다. 멀티 스레딩으로 인해 뮤텍스가 필요하지만 정의에 뮤텍스가 설명하는 상황에 특정한 것이라고 말하는 것은 없습니다.
alzclarke

1
뮤텍스의 공식적인 정의에 대해 정확합니다. 그러나 이것은 사람들이 현실 세계에서 뮤텍스에 대해 이야기 할 때 생각하는 것과 거의 다릅니다.
Ovesh

예상대로 작동하지 않습니다. 불행히도 반복 된 클릭은 여전히 ​​ajax 호출을 시작합니다. 다른 생각은 없나요?
Mohammed Shareef C

1
확신이은에 싸여해야 while으로 setTimeout또는 setInterval함께 clearInterval그래서 당신은 재시도 및 시간 제한 논리를 가지고 N 실패 후. 그대로 두는 것은 잠긴 코드를 우회한다는 의미입니다. 뮤텍스 및 공유 객체를 사용한 외부 처리는 구현 자체만큼 중요합니다.
MrMesees

6

JavaScript는 단일 스레드입니다 ... Chrome이 새로운 짐승 일 수 있지만 (나는 또한 단일 스레드라고 생각하지만 각 탭에는 자체 JavaScript 스레드가 있습니다 ... 자세히 살펴 보지 않았으므로 인용하지 마십시오. 그곳에).

그러나 걱정할 필요가있는 한 가지는 JavaScript가 보내는 것과 동일한 순서가 아닌 여러 개의 ajax 요청을 처리하는 방법입니다. 따라서 당신이 정말로 걱정할 필요가있는 것은 결과가 당신이 보낸 순서와 다른 순서로 돌아올 경우 서로의 발을 밟지 않는 방식으로 당신의 ajax 호출이 처리되는지 확인하는 것입니다.

이것은 시간 초과에도 적용됩니다 ...

JavaScript가 멀티 스레딩을 확장하면 뮤텍스 등에 대해 걱정할 수 있습니다 ....


4

예, localStorage 와 같이 탭 / 창간에 공유되는 리소스에 액세스 할 때 자바 스크립트에서 뮤텍스가 필요할 수 있습니다 .

예를 들어 사용자에게 두 개의 탭이 열려있는 경우 다음과 같은 간단한 코드는 안전하지 않습니다.

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

localStorage 항목이 'got'과 'set'이되는 시간 사이에 다른 탭에서 값을 수정했을 수 있습니다. 일반적으로 가능성은 낮지 만 가능합니다. 특정 상황에서 발생하는 경합과 관련된 가능성과 위험을 스스로 판단해야합니다.

자세한 내용은 다음 문서를 참조하십시오.


2

자바 스크립트, 언어 는 원하는만큼 멀티 스레드 될 수 있지만 자바 스크립트 엔진의 브라우저 임베딩은 한 번에 하나의 콜백 (onload, onfocus, <script> 등) 만 실행합니다 (아마도 탭당). 콜백 등록과 수신 사이의 변경을 위해 Mutex를 사용하라는 William의 제안은 문자 그대로 받아 들여서는 안됩니다. 콜백을 잠금 해제 할 콜백이 현재 콜백 뒤에 차단되기 때문에 중간 콜백에서 차단하고 싶지 않기 때문입니다. ! (와우, 영어는 스레딩에 대해 말하는 것이 싫습니다.)이 경우, 플래그가 문자 그대로 또는 setTimeout ()과 같이 설정된 경우 현재 이벤트를 다시 배포하는 라인을 따라 뭔가를 수행하고 싶을 것입니다.

다른 JS 임베딩을 사용하고 한 번에 여러 스레드를 실행하는 경우 조금 더 혼란 스러울 수 있지만 JS가 콜백을 매우 쉽게 사용하고 속성 액세스시 객체를 잠그는 방식으로 인해 명시 적 잠금이 거의 필요하지 않습니다. . 그러나 멀티 스레딩을 사용하는 일반 코드 (예 : 게임 스크립팅) 용으로 설계된 임베딩이 명시적인 잠금 기본 요소도 제공하지 않으면 놀랄 것입니다.

텍스트 벽에 죄송합니다!


0

이벤트는 신호를 받지만 JavaScript 실행은 여전히 ​​단일 스레드입니다.

내 이해는 이벤트가 신호를 받으면 엔진이 이벤트 핸들러를 실행하기 위해 실행중인 것을 중지한다는 것입니다. 핸들러가 완료되면 스크립트 실행이 재개됩니다. 이벤트 핸들러가 일부 공유 변수를 변경하면 재개 된 코드는 이러한 변경 사항이 "파란색"으로 나타나는 것을 볼 수 있습니다.

공유 데이터를 "보호"하려면 간단한 부울 플래그로 충분해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.