2013-07-06 1 views
0

В настоящее время я использую секундомер в качестве глобального таймера. У меня есть основной поток, другой поток и метод события. Основной поток запускает другой поток, и метод события запускается событиями. Оба метода будут вызывать секундомер и получать свое время. Дело в том, что времена не соответствуют: от основного потока: START REC AT 9282 STOP REC АТ 19290секундомер C# ведут себя по-разному в разных потоках?

из другого потока: аудио 1 аудио 304 аудио 354 аудио 404 аудио 444 аудио 494 аудио 544 аудио 594

от метода событий: видео 4 видео 5 видео 29 видео 61 видео 97 видео 129 видео 161

Я не понимаю, почему, если я начинаю свой ЗАП в 9282, две другие функции, которые требуют секундомера будут иметь таймеры, которые начинаются с нуля? Это проблема, связанная с потоком? Как я могу это исправить? Благодаря

UPDATE: * ** * ** * **

, когда я сохранить свои кадры я изменил: долго = relogio.EllapseMilliseconds я распечатать это значение и это нормально, как и ожидалось. но когда я печатаю значение, хранящееся в списках, они начинаются с начала. странно, да? ИЗБЕГАЙТЕ ДЛЯ ВСЕХ НЕИСПРАВНОСТЕЙ, Я ПЕЧАТАТЬ БЕЗ ЗАПУСКА, ПОЧЕМУ, ЧТО ОНИ ВСЕ СКАЗАЛИ НАЧАТЬ ИЗ НУЛЯ! МНОГИЕ СПАСИБО И ИЗБЕГАЙТЕ!

основной поток

private void Start_Recording_Click(object sender, RoutedEventArgs e) 
    { 

     rec_starting_time = relogio.ElapsedMilliseconds; 
     Console.WriteLine("START REC AT " + rec_starting_time); 
     write_stream.enableRecording(); 

     Thread a = new Thread(scheduleAudioVideoFramePicks); 
     a.Start(); 

scheduleAudioVideoFramePicks - это нить просто отсчитывает время, так что я знаю, когда остановиться

 //while.... 
     if (rec_starting_time + time_Actual > rec_starting_time+recording_time * 1000)//1000 - 1s = 1000ms 
      { 
       totalRecordingTimeElapsed = true; 
       write_stream.disableRecording(); 
       Console.WriteLine("STOp REC AT " + relogio.ElapsedMilliseconds); 
      } 
    //end while 
    lock (list_audio) 
     { 
     int b = 0; 
     //print time of frames gathered 
     foreach(AudioFrame item in list_audio){ 
      Console.WriteLine("audio " + (item.getTime() - rec_starting_time)); 
     } 
     lock (list_video) 
     { 
     } 
     foreach (VideoFrame item in list_video) 
     { 
      Console.WriteLine("video " + (item.getTime() - rec_starting_time)); 
     } 
     } 

другой поток, где я получаю время

 if (write_stream.isRecording()) 
      { 

       list_audio.Enqueue(new AudioFrame(relogio.ElapsedMilliseconds, audioBuffer)); 

      } 

метод события

   if (write_stream.isRecording()) 
        { 

         list_video.Add(new VideoFrame(relogio.ElapsedMilliseconds, this.colorPixels)); 


        }~ 

я не знаю, если это уместно, но я начинаю свой секундомер как этот

public MainWindow() 

    { 
     InitializeComponent(); 

     //some code 

     this.relogio = new Stopwatch(); 
     relogio.Start(); 

    } 
+5

Во-первых, «Секундомер» не является потокобезопасным. Во-вторых, невозможно диагностировать проблему без просмотра кода. – Lee

+0

Учитывая выбор между ошибкой в ​​секундомере или в коде, который его использует, очень просто обвинить код. Я знаю, что Секундомер работает, я не вижу ваш код. –

+0

отредактирован, чтобы включить код – virgula24

ответ

5

Секундомер не потокобезопасен, особенно для 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(); 
     } 
    } 
} 

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

+0

Я получаю значения, и они увеличиваются по строкам – virgula24

+0

@ virgula24 Это похоже на то, что 'секундомер' работает правильно в вашей системе, а это значит, что проблема, вероятно, лежит в вашем коде где-то. Вы должны попытаться использовать метод заблокированного доступа, чтобы получить прошедшее время, как в моем методе 'long elapsed()' выше. –

+0

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