2010-09-01 108 views
1

目前,我們使用供應商提供的非託管DLL來訪問特定的工具。感興趣的特定功能在頭文件中指定爲這樣:使用非託管DLL訪問衝突

extern "C" short CCONV acq_get_board_count(); 

在我的申請,我有PInvoke的說法:現在

public class bograms 
{ 
    [DllImport("bograms.dll", EntryPoint = "acq_get_board_count", CallingConvention = CallingConvention.StdCall)] 
    public static extern short acq_get_board_count(); 
} 

,在我的代碼,我試圖處理冗餘,所以我創建了試圖讓一切運行定時器:

public class Instrument 
{ 
    private System.Threading.Timer keepAliveTimer; 
    public Instrument() 
    { 
     keepAliveTimer = new Timer(new TimerCallback(this.KeepAlive), null, 0, 300000); 
    } 

    void KeepAlive(object state) 
    { 
     if(instrumentIsUninitialized) // some check that accomplishes this 
     { 
      Console.WriteLine("Some status statements"); // in console 
      short numBoards = bograms.acq_get_board_count(); 
      Console.WriteLine("Initialization caught {0} boards.", numBoards); // not in console 
     } 
    } 
} 

定時器的第一跳,它得到零塊板(大概是因爲硬件沒有完成初始化),一個d將這兩個消息打印到控制檯。但是,第二次打勾,我得到了bograms.dll中的APPCRASH錯誤0xc0000005,這是我發現的訪問衝突錯誤。將try/catch放在調用中並不會發現錯誤。第一行在控制檯中,第二行不在。在調試轉儲文件時(盡我所知有限),錯誤似乎發生在這次調用中。

我的口供錯誤是否錯誤?這是一個簡單的功能,我不敢相信它,但我錯過了什麼?計時器引起的線程是否會導致某些類型的問題?

我猜測第一次調用會將它置於某種導致第二次調用失敗的狀態,特別是當考慮在後臺進行硬件初始化時。如果是這種情況,有沒有辦法卸載驅動程序DLL,以便它可以重置回它應該在的初始狀態?

或者還有什麼其他的事情可以想到嗎?

回答

2

立即想到的一件事是API是否可以跨線程安全使用。 System.Threading.Timer回調進入ThreadPool線程,因此每次都可能會有所不同。一些API具有線程相關性要求,這意味着它們只能從單個線程中調用。代替這一點,如果同時發生兩個對同一個API的調用同時發生,那麼可能會有一些併發問題。最後你可能會發現這個問題與線程無關。我只是想提出一個可能的解釋。

+0

我知道這已經有一段時間了,但是我在過去一個月裏一直在測試這個理論,而且我認爲你對線程相關性的理解是正確的,特別是因爲我使用Timer來完成KeepAlive任務。儀器的驅動程序必須在第一次調用時存儲一些信息,而在第二次調用時(它發生在另一個線程上),它會嘗試訪問該位內存,並因違規而失敗。但是,我不知道如何解決這個問題...我是否使用'Thread.Sleep()'將每個KeepAlive的延時更改爲單循環?我聽說過關於睡覺的壞事... – drharris 2010-10-01 22:21:14

+0

你有沒有得到任何與此?我有完全相同的問題。 – Brandon 2014-07-23 14:30:01