2009-06-18 38 views
7

Tôi đã sử dụng một đa phương tiện Windows dll để tạo ra một bộ đếm thời gian độ phân giải cao vớiLàm cách nào để sử dụng CreateTimerQueueTimer để tạo bộ hẹn giờ có độ phân giải cao trong C#?

timSetEvent()

Nhưng trang timeSetEvent() đề nghị sử dụng:

CreateTimerQueueTimer()

thế nào có thể Tôi sử dụng CreateTimerQueueTimer() để thực hiện một phương thức mỗi 10 mili giây trong C#?

Trả lời

3

Gọi lại được chuyển đến CreateTimerQueueTimer được mong đợi là một hàm không được quản lý sẽ tồn tại trong suốt thời gian gọi lại. Người được ủy quyền quản lý có thể di chuyển trong bộ nhớ nhưng the underlying stub created by the marshalling will not do this so there is no need to pin the delegate. Tuy nhiên, cần phải giữ cho đại biểu không bị thu gom rác vì con trỏ từ mã không được quản lý không đủ để giữ cho nó tồn tại. Do đó, bạn phải đảm bảo rằng đại biểu được duy trì bởi một số tham chiếu được quản lý đang được duy trì (Có thể thông qua việc sử dụng GCHandle

Thông số PVOID được chuyển đến hàm gọi lại phải được sửa trong bộ nhớ từ lần nữa, chức năng không được quản lý mong đợi Nó không tự động di chuyển sau khi hàm trả về .Net này tự động xảy ra (hiệu quả) nhưng chỉ cho tuổi thọ của hàm được gọi, vì vậy nếu bạn đang sử dụng một tham chiếu đến một đối tượng được quản lý nào đó (nói bằng cách nhận IntPtr tới nó) đối tượng cơ bản phải được ghim (một lần nữa GCHandle có thể được sử dụng cho nó theo cách khác biệt) Để xem liệu đây có phải là vấn đề hay không, hãy thử sử dụng IntPtr.Zero làm tham số để kiểm tra xem nó có hoạt động hay không. gầy gs bạn sẽ cần phân bổ tham số của bạn dưới dạng byte thô trong vùng không được quản lý (và sắp xếp theo thứ tự), sử dụng một số loại blittable an toàn để đưa vào thứ gì đó có kích thước PVOID (như Int32) hoặc sử dụng kỹ thuật GCHandle ở trên để duy trì con trỏ ổn định đến một thể hiện được quản lý, điều này sẽ có ý nghĩa hiệu suất đáng kể nếu được thực hiện sai.

+0

Bạn thường không phải ghim đại biểu được chuyển đến các hàm API, vì InteropServices xử lý nội dung đó. Bạn * làm * phải đảm bảo rằng ứng dụng của bạn duy trì một tham chiếu đến đại biểu để nó không được thu thập rác. Ghim thường chỉ cần thiết khi truyền khối lượng bộ nhớ từ thế giới được quản lý vào thế giới không được quản lý (hy vọng mọi thứ ở lại nơi chúng). – MusiGenesis

+0

@MusiGenesis, đây là những gì tôi đã được đề cập đến bởi "Trong. Net này gần như chắc chắn xảy ra với bất cứ điều gì bạn vượt qua.", Tôi có lẽ nên có được gọi là ra như là cụ thể cho PInvoke. Tương tự như vậy tôi thấy không có lý do để đề cập đến sự cần thiết phải giữ một tài liệu tham khảo vì P/Gọi làm điều đó cho bạn nếu nó được yêu cầu: http://msdn.microsoft.com/en-us/23acw07k.aspx – ShuggyCoUk

+0

PInvoke chắc chắn không duy trì đại biểu tài liệu tham khảo cho bạn. Trình biên dịch sẽ vui vẻ cho phép bạn gọi hàm CreateTimerQueueTimer và truyền vào 'new TimerCallback (...)' làm tham số. Điều này thậm chí sẽ chạy thành công trong một thời gian, cho đến khi đại biểu bạn tạo với 'mới' xảy ra là rác được thu thập. – MusiGenesis

9

Đây là một liên kết đến một # wrapper C cho CreateTimerQueueTimer:

http://social.msdn.microsoft.com/Forums/en-CA/csharpgeneral/thread/822aed2d-dca0-4a8e-8130-20fab69557d2

(cuộn xuống đến bài cuối bởi Hobz cho lớp mẫu)

Tôi chỉ cố gắng này ra bản thân mình và nó hoạt động tốt. Tuy nhiên, một điều bạn cần phải thêm là gọi tới timeBeginPeriod(1) trước khi bắt đầu hẹn giờ để đặt hệ thống của bạn ở độ phân giải cao. timeSetEvent gọi timeBeginPeriod nội bộ, đó là lý do tại sao một số người nhầm lẫn cho rằng nó tạo ra bộ hẹn giờ có độ phân giải cao hơn.

+1

@ MusiGenesis- Tôi đã cố gắng sử dụng mã này, nhưng tôi nhận được một ngoại lệ stackoverlow. và bạn có ý gì khi 'gọi tới timeBeginPeriod (1)'? Tôi không thể tìm thấy một chức năng như vậy – sura

2

Tốt hơn nên sử dụng timeSetEvent vì kết quả của nó nhất quán hơn. Trên phần cứng hiện đại trung bình, trong khoảng thời gian nhỏ, độ lệch trong khoảng thời gian nhỏ hơn khoảng 10 lần so với khi sử dụng CreateTimerQueueTimer. Và đó là giả sử bạn không quên tăng độ phân giải hẹn giờ trước khi gọi CreateTimerQueueTimer, nếu không sự khác biệt sẽ còn lớn hơn. Vì vậy, hãy sử dụng timeSetEvent để thay thế.

Các vấn đề liên quan