繁体   English   中英

窗户上的虚假唤醒。 可能吗?

[英]Spurious wakeups on windows. Is it possible?

我最近学到了“虚假唤醒”任何人都说这个问题只适用于某些类型的Linux PC。

我用的是Windows。

我写了Spurious唤醒测试。 我得到的结果是可能的。 但我想为你展示这个测试。 也许我在某处弄错了。

我最初的变种:

import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class TestSpuriousWakeups {
    static final int MAX_THREADS = 600;

    static final Object mutex = new Object();

    static final CountDownLatch allThreadsStarted =
            new CountDownLatch(MAX_THREADS);
    static final CountDownLatch allThreadsFinished =
            new CountDownLatch(1);

    static /*final*/ volatile AtomicInteger processedThreads = new AtomicInteger();
    static /*final*/ volatile AtomicInteger notifiedThreads = new AtomicInteger();

    final  int n  = 10;

    static volatile boolean continueCondition = true;

    static final Random sleepRandom = new Random();

    static class Worker extends Thread {
        public void run() {
            try {
                synchronized (mutex) {
                    allThreadsStarted.countDown();

                    mutex.wait();
                }

                continueCondition = true;
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                processedThreads.incrementAndGet();
            }
        }
    }

    static class Notifier extends Thread {
        public void run() {
            while (true) {

                if (processedThreads.get() == MAX_THREADS)
                    break;

                synchronized (mutex) {
                    doStuff();

                    mutex.notify();
                    continueCondition = false;
                    notifiedThreads.incrementAndGet();
                }
            }

            allThreadsFinished.countDown();
        }

        // just to emulate some activity
        void doStuff() {
            try { Thread.sleep(sleepRandom.nextInt(5)); }
            catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < MAX_THREADS; i++)
            new Worker().start();

        // wait for all workers to start execution
        allThreadsStarted.await();

        new Notifier().start();

        // wait for all workers and notifier to finish execution
        allThreadsFinished.await();

        System.out.println("Spurious wakeups count: "
                + (MAX_THREADS - notifiedThreads.get()));
    }
}

4随机执行:

Spurious wakeups count: -20
Spurious wakeups count: -5
Spurious wakeups count: 0
Spurious wakeups count: -407

所以不同的价值观让我感到疑惑。

我添加了一对行来运行方法:

static class Notifier extends Thread {
        public void run() {
            while (true) {

                while (!continueCondition)  //added string
                    doStuff();              //added string            

                // all threads finished their execution
                if (processedThreads.get() == MAX_THREADS)
                    break;

                synchronized (mutex) {
                    doStuff();

                    mutex.notify();
                    continueCondition = false;
                    notifiedThreads.incrementAndGet();
                }
            }

            allThreadsFinished.countDown();
        }

在它之后,我不能得到别的东西

Spurious wakeups count: 0

我的实验真的是虚假的唤醒或错误吗?

PS

我注意到我看到负数。 因此显然它是实验bug。 但我不明白原因。

两件事情

  1. 即使在Windows上,虚假唤醒也是真实的。 这在WinAPI中有记录: http//msdn.microsoft.com/en-us/library/windows/desktop/ms682052( v = vs.85) .aspx
  2. 你的考试中有竞争条件。 所以,我认为这不是很准确。

竞争是在工作线程中同步块的退出与它们到达processedThreads.incrementAndGet()之间。 通知程序将在此期间旋转,通知可能已获取或未获得锁定的线程。

换一种说法

  1. 在工作者线程可以获取互斥锁之前,Notifier可能会旋转两次(即notify()两次)。
  2. 在最后一个线程退出同步块但尚未到达其finally块之后,Notifier可能会旋转。

你添加的两行会改变输出,因为通过减慢通知程序,你就会掩盖比赛。 (通过给工人很多时间进入互斥锁。)

希望这有点道理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM