StopWatch для нескольких потоков [дубликат]

Вам действительно нужно сделать это из папки src. Там вы вводите следующую командную строку:

[name of the package].[Class Name] [arguments]

Допустим, ваш класс называется CommandLine.class, и код выглядит следующим образом:

package com.tutorialspoint.java;

    /**
     * Created by mda21185 on 15-6-2016.
     */

    public class CommandLine {
        public static void main(String args[]){
            for(int i=0; i<args.length; i++){
                System.out.println("args[" + i + "]: " + args[i]);
            }
        }
    }

Затем вы должны cd в папку src и команда, которую вам нужно запустить, будет выглядеть так:

java com.tutorialspoint.java.CommandLine this is a command line 200 -100

И вывод в командной строке будет:

args[0]: this
args[1]: is
args[2]: a
args[3]: command
args[4]: line
args[5]: 200
args[6]: -100
0
задан virgula24 6 July 2013 в 21:16
поделиться

1 ответ

Секундомер не является потокобезопасным, особенно для 32-разрядных программ.

Он использует вызов Windows API QueryPerformanceCounter() для обновления частного длинного поля. В 32-битных системах вы можете получить «рваное чтение», когда один поток читает длинное значение, а другой поток обновляет его.

Чтобы исправить это, вам нужно будет заблокировать доступ к Секундомер.

Также обратите внимание, что в некоторых старых системах были ошибки, в которых непоследовательные значения могли быть возвращены из разных потоков, вызывающих QueryPerformanceCounter(). Из документации:

На многопроцессорном компьютере не должно иметь значения, какой процессор вызывается. Тем не менее, вы можете получить разные результаты на разных процессорах из-за ошибок в базовой системе ввода / вывода (BIOS) или слоя абстракции аппаратного обеспечения (HAL). Чтобы указать сродство процессора к потоку, используйте функцию SetThreadAffinityMask.

Я никогда не сталкивался с этой ошибкой сам, и я не думаю, что это очень распространено.

Какие результаты вы получаете со следующей тестовой программой? Время должно быть в основном возрастающим по стоимости, но вы можете получить один или два порядка, просто потому, что их потоки будут перенесены после того, как они прочитают значение и до того, как они добавят его в очередь.

namespace Demo
{
    class Program
    {
        Stopwatch sw = Stopwatch.StartNew();

        object locker = new object();
        ConcurrentQueue<long> queue = new ConcurrentQueue<long>();
        Barrier barrier = new Barrier(9);

        void run()
        {
            Console.WriteLine("Starting");

            for (int i = 0; i < 8; ++i)
                Task.Run(()=>test());

            barrier.SignalAndWait(); // Make sure all threads start "simultaneously"
            Thread.Sleep(2000); // Plenty of time for all the threads to finish.

            Console.WriteLine("Stopped");

            foreach (var elapsed in queue)
                Console.WriteLine(elapsed);

            Console.ReadLine();
        }

        void test()
        {
            barrier.SignalAndWait(); // Make sure all threads start "simultaneously".

            for (int i = 0; i < 10; ++i)
                queue.Enqueue(elapsed());
        }

        long elapsed()
        {
            lock (locker)
            {
                return sw.ElapsedTicks;
            }
        }

        static void Main()
        {
            new Program().run();
        }
    }
}

Сказав все это, наиболее очевидным ответом является то, что на самом деле вы не используете один секундомер между потоками, но вместо этого вы случайно запустили новый для каждого потока ...

5
ответ дан Matthew Watson 25 August 2018 в 12:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: