Javascript信号量/测试和设置/锁定?

时间:2009-02-17 00:51:22

标签: javascript concurrency semaphore

Javascript中是否存在原子测试和设置,信号量或锁定这样的事情?

我有javascript通过自定义协议调用异步后台进程(后台进程实际上在一个单独的进程中运行,与浏览器无关)。我相信我遇到了竞争状态;后台进程在我的测试和我的设置之间返回,在javascript端搞砸了。我需要一个测试和设置操作来使它成为一个真正的信号量。

以下是尝试检测后台进程并将其排队的javascript代码:

Call = function () {

var isRunning = true,
    queue = [];

return  {
    // myPublicProperty: "something",

    call: function (method) {
            if (isRunning) {
                console.log("Busy, pushing " + method);
                queue.push(method);
            } else {
                isRunning = true;
                objccall(method);
            }
        },

        done: function() {
            isRunning = false;
            if (queue.length > 0) {
                Call.call(queue.shift());
            }
        }
    };
}();

Call是一个实现排队的单例;任何想要调用外部进程的人都会调用Call.call(“something”)。

有什么想法吗?

7 个答案:

答案 0 :(得分:20)

JavaScript没有锁定语义,因为JS不是多线程语言。多个线程只能在完全不同的上下文中同时操作 - 例如。 HTML5工作线程,或者像JavaScriptCore API的上下文对象的多个实例(我假设SpiderMonkey有类似的概念)。它们不能具有共享状态,因此实质上所有执行都是原子的。

好的,因为您现在已经提供了一些代码,我假设您有类似的内容:

External Process:
<JSObject>.isRunning = true;
doSomething()
<JSObject>.done()

或某些此类(使用适当的API)。在这种情况下,如果JS在js对象的上下文中执行(这是JavaScriptCore会做的事情),我希望JS引擎能够阻塞,如果失败,你可能需要在js执行周围放置一个手动锁。

你用什么引擎来做这一切?我问,因为基于你的描述,听起来你正在使用该语言提供的C / C ++ API从非JS语言的辅助线程设置一个标志,并且大多数JS引擎都假设通过API进行的任何状态操作将发生在一个线程上,通常是所有执行发生的相同线程。

答案 1 :(得分:2)

也许你可以实现一个基本的整数信号量,只需将变量添加到DOM中并锁定/解锁它,并确保你的函数继续检查它,否则超时它们=)

如果您使用的是Mootools等框架,您可以尝试使用onComplete等事件来处理应用程序的流程。

答案 2 :(得分:1)

首先,虽然javaScript是单线程的,但javaScript应用程序不需要任何序列化机制。

一个简单的例子,就是当一个提交按钮淡出一段时间,在这段时间内,对服务器的Ajax请求正在运行。当异步Ajax请求成功完成时,消息应该出现在按钮的位置。

虽然能够取消按钮的淡出并简单地将其样式设置为&#34; display:none&#34;,但是一旦Ajax请求完成,这是不可能的,这是不可能的jQuery的。此外,解决方案可以使用事件来同步两个同时进行的活动,但这对于一个简单的问题来说实际上是过度的。

低技术解决方案是轮询锁定,当淡出完成时,它会被解锁,但服务器已完成&#34;在$ .post设置的成功回调执行之前,不会显示消息。

var gl_lock;
var gl_selfID;

function poll_lock(message) {
     if (gl_lock === 0) {
          $('#output').text(message).fadeIn(200);
          window.clearInterval(gl_selfID);
     }
 } // end of poll_lock

 function worker() {

     // no one gets in or out
     gl_lock = 1;

     $.post(..., data,function() { 
           gl_selfID = window.setInterval(poll_lock, 40, data.message);
      }, "json");

     // end of fadeout unlock the semaphore
     $('#submit-button').fadeOut(400, function() { gl_lock = 0; });

  } // end of worker

最后,我认为这是更详细的答案,与先前在本次讨论中由perrohunter提出的一致。

答案 3 :(得分:1)

我不确定问题究竟是什么,但请查看我的信号量对象:https://github.com/agamemnus/semaphore.js

答案 4 :(得分:0)

我有ajax填充选择列表的东西,我需要它被锁定所以我做了这样的事情。我认为你可以更简单地使用延迟和管道或其他东西。

var semaphore=[];

function myFunc(arg){
   var dfd;
   $.when(semaphore[table]).done(
      function(){
            dfd=myFuncInner(arg);
      }
      );
return dfd;
}

function myFuncInner(table){
semaphore[arg] = new $.Deferred();
... 
somethingasynchronous({
    semaphore[arg].resolve();
});

return  semaphore[arg];
}

答案 5 :(得分:0)

我遇到了同样的问题,这是我如何解决的。对于两个并发进程,它工作正常。如果您有三个或三个以上的进程,则两个进程可能会同时启动。

var isRunning = false;
...
var id = setInterval(function(){ //loop until isRunning becomes false
            if (!isRunning){
                isRunning = true;
                //do something synchronous or use a promise
                isRunning = false;
                clearInterval(id); // stop the loop here
            }
        , 10);

它比while循环更好,因为它解决了读取/设置isRunning的并发/异步问题。

答案 6 :(得分:0)

我使用 async-mutex 包来解决 Expo SQLite not blocking BEGIN TRANSACTION in iOS 的问题。您创建互斥锁并将临界区包装在 runExclusive 方法

    return this.mutex.runExclusive(async () => {
      try {
        await this.executeSqlAsync('begin immediate transaction');
        const tx = new AsyncSQLTransaction(this);
        const rs = await callback(tx);
        await this.executeSqlAsync('commit');
        return rs;
      } catch (error) {
        await this.executeSqlAsync('rollback');
        throw error;
      }
    });