討論區快速選單
知識庫快速選單
傑米的攝影旅遊筆記 網路投保旅行平安險 政府補助!學嵌入式+物聯網
[ 回上頁 ] [ 討論區發言規則 ]
dll event call back 的問題
更改我的閱讀文章字型大小
作者 : kuolung(kuolung)
[ 貼文 143 | 人氣 1414 | 評價 130 | 評價/貼文 0.91 | 送出評價 35 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/10/25 下午 12:46:46
請問一個有關 dll 的 event call back 的問題,

我寫了一個 dll 給第三方程式使用,
我的這個 dll 會再建立一個 workthread 來抓資料,

請問,當我的 workthread 抓到資料後,如何 call back 鈶我的 dll 程式,

我以前的做法是,
我的主程式不是 dll 而是 exe
我只要在 exe 中放一個全域變數,指到自己的 hwnd 叫 pHwnd
在 workthread 中用 postmessage(pHwnd, xx, xx);
方式就可以收到 workthread 抓到資料的 callback

但是主程式不是 exe , 好像沒有 message queue 來收 message
作者 : ice_emissary(燃燒的大地) 貼文超過200則
[ 貼文 345 | 人氣 0 | 評價 1650 | 評價/貼文 4.78 | 送出評價 16 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人kuolung註記此篇回應為很有道理 2017/10/25 下午 02:28:31
你在呼叫函式建立執行緒的時候,不是有一個使用者參數嗎?比如說:

    int thrd_create( thrd_t *thr, thrd_start_t func, void *arg );

那個 arg 參數就是讓執行緒建立者與執行緒溝通用的東西!
你可以傳入任何東西,新的執行緒的執行函式(func)就會收到這個東西,然後建立執行緒的地方也有這個東西(因為就是它把參數傳入的不是?)
然後兩個執行緒就可以透過它交換資料了!
作者 : kuolung(kuolung)
[ 貼文 143 | 人氣 1414 | 評價 130 | 評價/貼文 0.91 | 送出評價 35 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/10/25 下午 04:25:59
可是,我 WorkThread 是用如下的方式建立的

WorkThread 的宣告

Uint WorkThread( LPvoid pParam )
{
// Thread 的程式
...
}


主 dll 建立 WorkThread 並啟動

pThreadCom = AfxBeginThread(WorkThread, NULL, THREAD_PRIORITY_NORMAL);
作者 : kuolung(kuolung)
[ 貼文 143 | 人氣 1414 | 評價 130 | 評價/貼文 0.91 | 送出評價 35 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/10/25 下午 04:32:32
所以我可以在

AfxBeginThread(WorkThread, NULL, THREAD_PRIORITY_NORMAL);

的第二個參數,原本是 NULL 的地方,加入我的 callback function 的指標
然後在

WorkThread 用它去 callback

有沒有比較詳情的語法範例

例如,我的 callback function

int DataComing(int index, int data)
{
}

請問要如何宣告,如何 callback

作者 : ice_emissary(燃燒的大地) 貼文超過200則
[ 貼文 345 | 人氣 0 | 評價 1650 | 評價/貼文 4.78 | 送出評價 16 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/10/25 下午 04:34:16
>可是,我 WorkThread 是用如下的方式建立的
> ......
>pThreadCom = AfxBeginThread(WorkThread, NULL, THREAD_PRIORITY_NORMAL);

方法是一樣的,AfxBeginThread 的第二個參數 pParam 就是會傳給 pfnThreadProc 的參數,官方說明就有寫到了:
https://msdn.microsoft.com/zh-tw/library/s3w9x78e.aspx

不管你是用 thrd_create、pthread_create、CreateThread、_beginthreadex、還是 AfxBeginThread 來建立執行緒,
它們都有一樣的參數傳遞機制。
作者 : ice_emissary(燃燒的大地) 貼文超過200則
[ 貼文 345 | 人氣 0 | 評價 1650 | 評價/貼文 4.78 | 送出評價 16 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人kuolung註記此篇回應為最佳解答 2017/10/25 下午 04:42:31
你要範例嗎?

struct WorkData
{
    void *UserArg;
    void(*UserFunc)(void *UserArg);
    int MyFlag;
};

Uint WorkThread(struct WorkData *data)
{
    // Thread 的程式
    ...
    data->MyFlag = 7;
    data->UserFunc(data->UserArg);
    ...
}


//主 dll 建立 WorkThread 並啟動

struct WorkData exgdata =
{
    .UserArg = UserArg, // UserArg 是由使用者給你的參數,讓你可以把他 pass 回使用者 callback,就像執行緒把 pParam pass 給你一樣。
    .UserFunc = UserFunc, // UserFunc 是由使用者給你的 callback 函式。
    .MyFlag = 0,
};

pThreadCom = AfxBeginThread((UINT(*)(LPvoid)) WorkThread, &exgdata, THREAD_PRIORITY_NORMAL);
作者 : ma_hty(白老鼠(Gary))討論區板主 OpenGL卓越專家DirectX優秀好手C++頂尖高手貼文超過2000則人氣指數超過70000點
[ 貼文 2160 | 人氣 89850 | 評價 10080 | 評價/貼文 4.67 | 送出評價 78 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人kuolung註記此篇回應為很有道理 2017/10/25 下午 06:23:59
>請問,當我的 workthread 抓到資料後,如何 call back 給我的 dll 程式,...

一般的做法, 有兩種, 一是 由DLL主動傳資料, 另一是 由主程式被動地收資料.

由DLL主動傳資料的話, 你可以先在 DLL裡, 定義一個 function pointer 變數,
在使用前, 主程式把自己某個對應 function prototype 的函數, 傳給 DLL.
如此, DLL 就可以按需要呼叫該函數 經函數的變數 去傳遞資料.

在 DLL:
void (*my_receive_func)(const char *str) = NULL; // function pointer 變數
void RegisterReceiveFunc( void (*func)(const char*str) ) // 這函數需要被匯出
{
  my_receive_func = func;
}
void send_some_str_to_main()
{
  if(my_receive_func)
    my_receive_func( "HIHI" );
}

在主程式:
void my_receive(const char *str)
{
  printf( "%s\n", str );
}
void main()
{
  RegisterReceiveFunc(my_receive);
}

由主程式被動地接收資料的話, 你可以先在 DLL裡, 多匯出一個函數,
讓主程式間歇性地重複呼叫它. 然後, 同樣也是經 函數的變數
去傳遞資料. 可是... 雖然這較簡單, 但是 被動地接收資料 不太好.

另外, 你提及過 "workthread" (><" 應該說 worker thread 的), 想
必有多執行緒的程序吧. 上面的做法, 未考慮同步的問題, 請注意.
作者 : kuolung(kuolung)
[ 貼文 143 | 人氣 1414 | 評價 130 | 評價/貼文 0.91 | 送出評價 35 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/10/27 下午 04:45:17
謝謝您,依照您提供的範例,確實可行,
只是,好像還是有一點問題,因為我的是 MultiThread 的程式,

用 data->MyFunct(...) 的方式,是不是會有兩個 Thread 在同一個記憶區域,工作,會不會有問題
作者 : ice_emissary(燃燒的大地) 貼文超過200則
[ 貼文 345 | 人氣 0 | 評價 1650 | 評價/貼文 4.78 | 送出評價 16 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/10/27 下午 08:08:29

>只是,好像還是有一點問題,因為我的是 MultiThread 的程式,
>用 data->MyFunct(...) 的方式,是不是會有兩個 Thread 在同一個記憶區域,工作,會不會有問題

你說的不錯,多執行緒共同存錢資料確實會有些問題需要被克服,老鼠兄也有提醒你這點!
但這是另外一個議題了,蠻大的題目!
你可另外搜尋有關「執行緒資料競爭」的文章或討論來學習。

但我們也已經回答了你最初的問題,現在兩個執行緒可以共通資料了,剩下就是資料規劃以及共同存取保護的工作。
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1003 | 人氣 3227 | 評價 1260 | 評價/貼文 1.26 | 送出評價 27 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/10/28 上午 01:22:33

>在 workthread 中用 postmessage(pHwnd, xx, xx);
>方式就可以收到 workthread 抓到資料的 callback
>
>但是主程式不是 exe , 好像沒有 message queue 來收 message

若你確定 exe 沒有問題,把 hwnd 傳給 DLL ,就能一樣的方式回傳
作者 : ice_emissary(燃燒的大地) 貼文超過200則
[ 貼文 345 | 人氣 0 | 評價 1650 | 評價/貼文 4.78 | 送出評價 16 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/10/30 上午 10:52:13
>若你確定 exe 沒有問題,把 hwnd 傳給 DLL ,就能一樣的方式回傳

做為一個 DLL,你怎麼能確定 EXE 一定有一個 window?甚至,你怎麼能肯定呼叫者一定是一個 EXE?
這不就是做為一個程式庫的基本要求嗎?寫程式庫相較於寫終端執行程式是有更多的廣泛適用需求需要被考慮的!

以前遇過一個日本人寫的 DLL 就非常令人忿怒,我完全按照他的程式庫說明來建立測試程式,卻怎樣也收不到資料!
過了一週後靈機一動,在主程式裡加了一個 Windows 事件處理迴圈,資料就收到了……
原來問題是我的測試程式是一隻 console 程式,而他的 DLL 需依賴 Windows 消息傳遞機制來運作。
設計出這樣的程式庫本身就應該被罵兩圈,沒有意識到要把這樣的使用限制寫進手冊不知道能不能直接開火這個人?
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1003 | 人氣 3227 | 評價 1260 | 評價/貼文 1.26 | 送出評價 27 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/10/30 上午 11:53:20

>我以前的做法是,
>我的主程式不是 dll 而是 exe
>我只要在 exe 中放一個全域變數,指到自己的 hwnd 叫 pHwnd
>在 workthread 中用 postmessage(pHwnd, xx, xx);
>方式就可以收到 workthread 抓到資料的 callback

我是依樓主這段回覆,若是 multithread 不管是 exe 還是 dll 都會有許多問題要處理,但用 postthreadmessage 把處理方法都丟給主線程會比較簡單,但若假設不一定給 windows 訊息迴圈使用,那真的得做許多功課
作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/11/29 下午 05:47:44
>用 data->MyFunct(...) 的方式,是不是會有兩個 Thread 在同一個記憶區域,工作,會不會有問題
會提這個問題,表示對程式邏輯敏感度不錯。
所有多緒程式都要靠訊號機來處理資料競爭的問題,
有一本書"多緒程式設計"專門討論這個問題,建議你可以以買一本研讀。
在還沒把握在多緒中控制資料存取的秩序前,建議先不要冒然為之。很難debug...
你的問題應該可以用較簡單的方式解決,例如:
把要傳達的訊息用windows message丟給主程式,主程式收到message再通知DLL即可。
前面有網友提到,主程式不一定是有windows的程式,那並不重要。
message driven 的觀念,是以執行緒對應,不是window。也就是說一個執行緒就有權擁有自己的message queue。
事實上一個執行緒可能建立多個window,這些window都是共用同一個執行緒的message queue。
windows的規則是,當某個執行緒第一次試圖讀取本身的message queue,windows 系統就會配發一個message queue給該執行緒。
(這可以避免不需message queue的執行緒浪費資源,需要時,系統會及時建立)
所以若主程式(或主執行緒),不是windows並沒有關係,只要在在程式竹的主循環裡去輸詢message queue(PeekMessage/GetMessage)就可以收到
其它程式丟過來的message(即便不是同一個執行緒)。

作者 : sunyear(coco) VC++卓越專家C++頂尖高手貼文超過2000則
[ 貼文 2421 | 人氣 1485 | 評價 6060 | 評價/貼文 2.5 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/11/29 下午 05:55:57
>在主程式裡加了一個 Windows 事件處理迴圈,資料就收到了
那是message 讀取和分發的迴圈,包括但不限於處理windows事件的訊息。
別人傳過來的訊息是放在message queue,執行緒程式要自己去讀message queue。
 板主 : 青衫 , Raymond
 > Visual C++ - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - Visual C++ - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
Visual C++
1 青衫 11070 
2 Raymond 10090 
3 Clier 7630 
4 小約翰 2500 
5 Cog 2030 
6 coco 1870 
7 aming 1410 
8 牧童哥 1400 
9 r2109 1380 
10 Akira 1350 
Visual C++
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2018 程式設計俱樂部 http://www.programmer-club.com.tw/
0.171875