多线程正确性:使用同步块

发布于 2024-12-25 19:44:16 字数 2015 浏览 1 评论 0原文

我正在使用 CMU Sphinx 语音识别器库(源链接)使用了一些同步块。

RecognizerTask 中的一个示例块:

Event mailbox;

[...]

public void start() {
    synchronized (this.mailbox) {
        this.mailbox.notifyAll();
        this.mailbox = Event.START;
    }
}

代码运行没有任何问题,但是 BugFinder 给出了以下警告:

错误:RecognizerTask.mailbox 上的同步尝试无效 守护它

此方法在看似是一个字段的字段上进行同步 尝试防止同时更新该字段。但 保护字段会获得引用对象上的锁,而不是对象上的锁 场地。这可能无法提供您需要的互斥,并且其他 线程可能正在获取引用对象上的锁(对于其他对象) 目的)。这种模式的一个例子是:

private Long myNtfSeqNbrCounter = new Long(0);
私有长 getNotificationSequenceNumber() {
     长结果 = null;
     同步(myNtfSeqNbrCounter){
         结果 = new Long(myNtfSeqNbrCounter.longValue() + 1);
         myNtfSeqNbrCounter = new Long(result.longValue());
     }
     返回结果;
 }

说实话,我不太明白错误描述以及在这种情况下应该出现什么问题。 全局变量不是字段吗?如果没有,我该如何改进代码?

/edit: 这是调用 Event.wait() 的唯一部分:

Event todo = Event.NONE;
        synchronized (this.mailbox) {
            todo = this.mailbox;
            /* If we're idle then wait for something to happen. */
            if (state == State.IDLE && todo == Event.NONE) {
                try {
                    //Log.d(getClass().getName(), "waiting");
                    this.mailbox.wait();
                    todo = this.mailbox;
                    //Log.d(getClass().getName(), "got" + todo);
                } catch (InterruptedException e) {
                    /* Quit main loop. */
                    //Log.e(getClass().getName(), "Interrupted waiting for mailbox, shutting down");
                    todo = Event.SHUTDOWN;
                }
            }
            /* Reset the mailbox before releasing, to avoid race condition. */
            this.mailbox = Event.NONE;
        }

此代码实际上也使用 synchronized 语句。使用它有意义吗?

I am using the CMU Sphinx Speech Recognizer library (Link to source) that makes some use of synchronized blocks.

One example block from the RecognizerTask:

Event mailbox;

[...]

public void start() {
    synchronized (this.mailbox) {
        this.mailbox.notifyAll();
        this.mailbox = Event.START;
    }
}

The code works without any problems, however BugFinder gives this warning:

Bug: Synchronization on RecognizerTask.mailbox in futile attempt to
guard it

This method synchronizes on a field in what appears to be an
attempt to guard against simultaneous updates to that field. But
guarding a field gets a lock on the referenced object, not on the
field. This may not provide the mutual exclusion you need, and other
threads might be obtaining locks on the referenced objects (for other
purposes). An example of this pattern would be:

private Long myNtfSeqNbrCounter = new Long(0);
private Long getNotificationSequenceNumber() {
     Long result = null;
     synchronized(myNtfSeqNbrCounter) {
         result = new Long(myNtfSeqNbrCounter.longValue() + 1);
         myNtfSeqNbrCounter = new Long(result.longValue());
     }
     return result;
 }

To be honest, I don't quite understand the bug description and what is supposed to be wrong in this case.
Is a global variable not a field? And if not, how can I improve the code?

/edit: This is the only part where Event.wait() is called:

Event todo = Event.NONE;
        synchronized (this.mailbox) {
            todo = this.mailbox;
            /* If we're idle then wait for something to happen. */
            if (state == State.IDLE && todo == Event.NONE) {
                try {
                    //Log.d(getClass().getName(), "waiting");
                    this.mailbox.wait();
                    todo = this.mailbox;
                    //Log.d(getClass().getName(), "got" + todo);
                } catch (InterruptedException e) {
                    /* Quit main loop. */
                    //Log.e(getClass().getName(), "Interrupted waiting for mailbox, shutting down");
                    todo = Event.SHUTDOWN;
                }
            }
            /* Reset the mailbox before releasing, to avoid race condition. */
            this.mailbox = Event.NONE;
        }

This code is actually using a synchronized statement as well. Does it make sense at all to use it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

骷髅 2025-01-01 19:44:16

同步块“捕获”给定对象的锁,在您的情况下是由 mailbox 表示的对象。一旦您将变量 mailbox 更改为指向不同的对象,其他线程就可以毫无问题地“捕获”该对象的锁,因为它没有被占用。

请注意,锁是针对对象的,而不是针对引用的!

现在,考虑以下[伪代码]:

synchronised (myObject) { 
  myObject = new Object();
  i += 5; //assume i is an instance variable
}

这里实际上没有锁!每个线程都在锁块中创建一个新对象,而i的修改是不同步的!

the synchronized block "captures" the lock for the given object, in your case for the object denoted by mailbox. Once you change the variable mailbox to point to a different object, other threads can "capture" the lock for this object without a problem, since it is not taken.

Note that the lock is for objects, and not for references!

now, concider the following [pseudo code]:

synchronised (myObject) { 
  myObject = new Object();
  i += 5; //assume i is an instance variable
}

practically there is no lock here! every thread is creating a new object in the lock block, and the modification of i is not synchronized!

吹梦到西洲 2025-01-01 19:44:16

我认为这不适用于你的情况。您调用了 notifyAll(),这意味着其他线程的代码中的某个位置有一个匹配的 wait() 调用:

synchronized (this.mailbox) {
    this.mailbox.wait();        
}

这意味着其他线程将放弃等待通知时锁定。

您的代码检查器可能会对以下行感到困惑:

this.mailbox = Event.START;

这意味着您可能正在同时修改此对象,这样,如果另一个线程尝试获取 this.mailbox 上的锁定,它将看到一个不同的对象。但是,我确实认为,因为:

  1. this.mailbox 是全局可见的,
  2. 引用的分配是原子的,
  3. 锁会生成栅栏,

所有线程都应该始终拥有同步对象的更新视图。

I don't think it applies in your case. You have a call to notifyAll() which means that somewhere in the code of the other threads there is a matching wait() call:

synchronized (this.mailbox) {
    this.mailbox.wait();        
}

meaning that the other thread will relinquish the lock while waiting to be notified.

Your code inspector is probably confused by the line:

this.mailbox = Event.START;

meaning that you might be concurrently modifying this object, such that if another thread attempts to get the lock on this.mailbox, it will see a different object. However, I do think that since:

  1. this.mailbox is globally visible
  2. assigns of references are atomic
  3. the lock generates a fence

all threads should have an updated view of the synchronization object at all times.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文