简体   繁体   English

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

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

I recently learned "Spurious wakeups" Any people say that this problem possible only for some types of Linux PC. 我最近学到了“虚假唤醒”任何人都说这个问题只适用于某些类型的Linux PC。

I use windows. 我用的是Windows。

I wrote test for Spurious wakeups. 我写了Spurious唤醒测试。 I got result that it is possible. 我得到的结果是可能的。 But I want to show this test for you. 但我想为你展示这个测试。 Maybe I made mistake somewhere. 也许我在某处弄错了。

my initial variant: 我最初的变种:

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 random execution: 4随机执行:

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

So different values is wondering for me. 所以不同的价值观让我感到疑惑。

I added pair of rows to run method: 我添加了一对行来运行方法:

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

after it I cannot get something another than 在它之后,我不能得到别的东西

Spurious wakeups count: 0

Is it really Spurious wakeups or bug in my experiment ? 我的实验真的是虚假的唤醒或错误吗?

PS PS

I noticed that I see negatives numbers. 我注意到我看到负数。 Thus obviously it is experiment bug. 因此显然它是实验bug。 But I don't understand cause. 但我不明白原因。

Two things 两件事情

  1. Spurious wake ups are real, even on Windows. 即使在Windows上,虚假唤醒也是真实的。 This is documented in the WinAPI: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682052(v=vs.85).aspx 这在WinAPI中有记录: http//msdn.microsoft.com/en-us/library/windows/desktop/ms682052( v = vs.85) .aspx
  2. You have a race condition in your test. 你的考试中有竞争条件。 So, I don't think it's quite accurate. 所以,我认为这不是很准确。

The race is between the exit of the synchronized block in your worker threads and when they reach processedThreads.incrementAndGet(). 竞争是在工作线程中同步块的退出与它们到达processedThreads.incrementAndGet()之间。 Notifier will spin during that time, notifying threads which may or may not have acquired the lock. 通知程序将在此期间旋转,通知可能已获取或未获得锁定的线程。

In other words 换一种说法

  1. It's possible for Notifier to spin twice (that is, notify() twice) before a worker thread can acquire the mutex. 在工作者线程可以获取互斥锁之前,Notifier可能会旋转两次(即notify()两次)。
  2. It's possible for Notifier to spin after the last thread has exited the synchronized block but not yet reached its finally block. 在最后一个线程退出同步块但尚未到达其finally块之后,Notifier可能会旋转。

Your two added lines change the output because, by slowing down the Notifier, you're masking the race. 你添加的两行会改变输出,因为通过减慢通知程序,你就会掩盖比赛。 (By giving Worker lots of time to enter the mutex.) (通过给工人很多时间进入互斥锁。)

Hope that makes some sense. 希望这有点道理。

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

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