2010-03-25 5 views
1

나는 인터넷 시간까지 동기화하기 위해 NTP 클라이언트를 사용하는 컴퓨터를 가지고있어서 시스템 클럭이 상당히 정확해야한다.N 밀리 초마다 작업을 (합리적으로) 정확하게 수행하려면 어떻게해야합니까?

실시간으로 데이터를 기록하고 처리 한 다음 전달하는 응용 프로그램이 있습니다. 지금 내가하고 싶은 것은 N 밀리 초마다 시스템 클럭에 맞춰진 데이터를 출력하는 것입니다. 내가 20ms의 간격을 원한다면 그래서 예를 들면, 내 oututs은 다음과 같이되어야한다 : 나는 스톱워치 클래스를 사용하기위한 제안을 본 적이

13:15:05:000 
13:15:05:020 
13:15:05:040 
13:15:05:060 

하지만, 특정 찾고 반대로 시간에 걸쳐 측정하는 타임 스탬프. 이를 수행하는 코드는 자체 스레드에서 실행되기 때문에 상대적으로 블로킹 호출을해야 할 경우에는 문제가되어야합니다.

이것을 달성하는 방법에 대한 제안 (1ms 정밀도에 가까운 것이 좋을 것입니다)은 매우 감사하게 받아 들여질 것입니다.

+3

Windows PC에서 이와 같이 정밀한 실시간 응용 프로그램을 만드는 것은 엄청난 기업이며, 나는 여러분에게 행운을 기원합니다. –

+0

나는 그 대답일지도 모른다고 생각했습니다. 완벽 할 필요는 없지만 더 가까워 질수록 깔끔한 솔루션을 얻을 수 있습니다. 언제든지 –

+0

국립 악기 데이터 수집 보드를 사용하고 있습니까? 그렇다면 하드웨어 타이머가 있으며 카드에 명령을 보내 yms 간격으로 x 번 획득을 정확하게 획득 할 수 있습니다. – MedicineMan

답변

2

그것이 C++/CLR을 재생하는 방법을 잘 몰라하지만 당신은 아마 할 것입니다 귀하의 응용 프로그램 multimedia timers,
Windows는 실제로 실시간이 아니지만 이보다 가깝습니다.

+0

커널 만이 실제로 무엇을 실행하는지 말할 수 있습니다. –

+0

그러나 디스크에 쓰지 않는 것으로 가정하면 50fps는 너무 많은 여분의 작업없이 괜찮은 컴퓨터에서 가능해야합니다. –

+0

버퍼링은 디스크 쓰기 문제를 해결할 수 있습니다. –

1

가장 좋은 건 인라인 어셈블리를 사용하고이 코드 덩어리를 장치 드라이버로 쓰는 것입니다.

그 방법 :

  • 당신은 명령 수를 제어 할 수
  • 실행 우선 순위
+0

마이크로 초 정도의 정확도가 필요하다면 예. 밀리 초의 정확도는 사용자 모드에서도 가능합니다. –

+0

질문에 "1ms 정밀도에 가깝거나 더 낫습니다." –

+0

1ms = 1000 마이크로 초 –

0

CreateWaitableTimer/SetWaitableTimer 및 우선 순위가 높은 스레드는 약 1ms 정확해야합니다. 나는 왜 예제 출력의 밀리 세컨드 필드가 네 자리수인지 모르겠다. 최대 값은 999이다 (1000ms = 1 초).

+0

네 자리 숫자가 양호합니다. 그냥 유형 :-) –

1

운영 체제가 다른 프로세스의 요청을 받아야하기 때문에 궁극적으로 원하는 것을 보장 할 수 없습니다. 즉, 프로세스를 실행하고 싶은 순간에 항상 다른 작업을 수행 할 수 있습니다. 그러나 timeBeginPeriod을 사용하여 문제를 개선하면 프로세스가 적시에 전환 될 가능성이 커지고 반복 사이에 대기하는 방법과 관련하여 교묘하게 느낄 수 있습니다. 대부분은 아니지만 모든 시간 동안 잠자고 나머지는 바쁜 루프를 사용합니다.

+0

나는 같은 줄을 따라 생각하고 있었다. –

1

두 개의 스레드에서이 작업을 시도해보십시오. 하나의 스레드에서 루프의 고정밀 타이머를 쿼리하려면 this과 같은 것을 사용하십시오. 20ms 경계에 맞춰 지거나 합리적으로 가까운 시간 소인을 발견하면 사용할 시간 소인과 함 2 로그 출력 스레드로 신호를 보내십시오. 로그 출력 스레드는 단순히 신호를 기다린 다음 전달 된 타임 스탬프를 가져와 필요한 모든 것을 출력합니다. 두 개의 스레드를 별도의 스레드로 유지하면 로그 출력 스레드가 타이머와 간섭하지 않게됩니다 (기본적으로 하드웨어 타이머 인터럽트를 에뮬레이션하므로 임베디드 플랫폼에서이를 수행 할 수 있습니다).

0

당신이 말했듯이, 이것이 완벽 할 필요는 없기 때문에 할 수있는 일이 있습니다.

내가 아는 한, 특정 시간과 동기화되는 타이머가 없습니다. 따라서 다음 시간을 계산하고 해당 특정 시간의 타이머를 예약해야합니다.타이머에 델타 지원 만 있으면 쉽게 계산할 수 있지만 델타를 계산하는 시간과 타이머가 커널에 입력 된 시간 사이에 CPU에서 쉽게 시작할 수 있기 때문에 더 많은 오류가 발생합니다.

이미 지적했듯이 Windows는 실시간 OS가 아닙니다. 따라서 ": 0010"에서 타이머를 예약하더라도 코드가 그 시간 (예 : "0540") 전까지는 실행되지 않을 수도 있다고 가정해야합니다. 이러한 문제를 적절하게 처리하는 한 모든 일이 "정상"입니다.

+0

대기 타이머는 실제로 델타가 아닌 알람 시간을 설정할 수있게 해준다. –

0

20ms는 대략 Windows의 시간 슬라이스 길이입니다. 윈도우에서 안정적으로 1ms 종류의 타이밍을 맞출 수있는 방법은 없습니다. Windows에서 적절한 옵션은 WaitForSingleObject, SleepEx 및 busy loop입니다.

+0

그러나 양자! = 타이머 인터럽트 속도. 우선 순위가 높은 스레드의 타이머는 타이머 인터럽트의 대략적인 정밀도를 가지므로 (더 높은 우선 순위의 작업이 활성화되어 있지 않은 한) 라운드 로빈 컨텍스트 스위칭이 수행되는 속도보다 상당히 좋습니다. –

2

기간을 줄이면 timeGetTime() 밖의 꽤 정확한 시간 소인을 얻을 수 있습니다. 반환 값을 시계 시간으로 변환하려면 몇 가지 작업 만 있으면됩니다. 이 샘플 C# 코드는 접근 방식을 보여줍니다.

using System; 
using System.Runtime.InteropServices; 

class Program { 
    static void Main(string[] args) { 
     timeBeginPeriod(1); 
     uint tick0 = timeGetTime(); 
     var startDate = DateTime.Now; 
     uint tick1 = tick0; 
     for (int ix = 0; ix < 20; ++ix) { 
      uint tick2 = 0; 
      do { // Burn 20 msec 
       tick2 = timeGetTime(); 
      } while (tick2 - tick1 < 20); 
      var currDate = startDate.Add(new TimeSpan((tick2 - tick0) * 10000)); 
      Console.WriteLine(currDate.ToString("HH:mm:ss:ffff")); 
      tick1 = tick2; 
     } 
     timeEndPeriod(1); 
     Console.ReadLine(); 
    } 
    [DllImport("winmm.dll")] 
    private static extern int timeBeginPeriod(int period); 
    [DllImport("winmm.dll")] 
    private static extern int timeEndPeriod(int period); 
    [DllImport("winmm.dll")] 
    private static extern uint timeGetTime(); 
} 

두 번째 생각에서 이는 단지 측정에 불과합니다. 주기적으로 수행되는 작업을 얻으려면 timeSetEvent()를 사용해야합니다. timeBeginPeriod()를 사용하는 한 콜백 기간을 1 밀리 초에 가깝게 얻을 수 있습니다. 한 가지 좋은 점은 이전 콜백이 어떤 이유로 늦었을 때 자동으로 보상 해주는 것입니다.

관련 문제