本帖最后由 edisonx 于 2012-11-16 17:51 编辑
這問題是微軟(Microsoft)的面試題,在工作管理員裡之 CPU 曲線圖,顯示 sin 圖形,小弟在 C 上作業正常,執行結果如下。
由於想熟悉 AutoIt 語法,轉成 AutoIt 後圖形變了樣
細思差別有幾個可能,不確定是哪種,想徵求不同網友之意見。
(1) 我的 code 有問題?
以下會附 AU3 code,但大致上都有進行過逐步確認、除錯,有錯機會大概不大(吧?)
(2) Main 裡最後之 dead loop
在 C 裡面, Main 裡最後不用卡一個 while(1); 在 Thread 被終止前主程序都會一定在跑。
但 AU3 裡面不放 While (nothing) WEnd 的話,主程序跑完時 Thread 似乎就會自動回收、自己跳出來,
而 while(1) 裡面要 Sleep 多少這個又難算了,試過幾個可能性數值 (no-sleep、sleep(1)、sleep(slic-time) 都失敗,
(3) 語言特性?
左思右想,dead loop 原因可能是最大 (雖這也是語言特性就是了),其次是 AU3 語言特性問題。語言特性又可能是,它的計算太慢,導致推導出之方法無法使用;
又或是如官網所說的:它不支援多行緒 (multi-thread),導致連一般的 Multi-Thread API 都出了問題?
由於 C language 非本論壇主要程式語言,對 C language src 有興趣玩玩可再留言,小弟將再附件。
附上 AU3 code,如下
#include <winapi.au3>
#include <array.au3>
Main()
; -----------------------------------------------------------------------
; Constant Define
Const $COUNT = 400
Const $SPLIT = 0.01
Const $PI = 3.14159265358979
Const $SLOPE = 150
Const $INTERVAL = 400
; -----------------------------------------------------------------------
; Dll Call
Func GetTickCount()
Local $ret = DllCall("kernel32.dll","int","GetTickCount")
return $ret[0]
EndFunc
Func CreateThread($pFunc)
Local $ret = 10
Local $hThreadId = DllStructCreate("DWORD")
Local $handle = DllCallbackRegister($pFunc, "int", "ptr")
Local $ret = DllCall("kernel32.dll","ptr","CreateThread", "ptr", 0, "dword", 0, "ptr", DllCallbackGetPtr($handle), "ptr", 0, "dword", 4, "dword*", 0)
return $ret[6]
EndFunc
Func SetThreadAffinityMask($hThread, $iProcessor)
Local $ret
$ret = DllCall("kernel32.dll", "DWORD", "SetThreadAffinityMask", "HANDLE", $hThread, "DWORD*", $iProcessor)
; ConsoleWrite(@error & @CRLF)
return $ret[0]
EndFunc
Func ResumeThread($hThread)
Local $ret = DllCall("kernel32.dll", "DWORD", "ResumeThread", "DWORD", $hThread)
; ConsoleWrite(@error & @CRLF)
return $ret[0]
EndFunc
Func GetCurrentThread()
Local $ret = DllCall("kernel32.dll", "HANDLE", "GetCurrentThread")
; ConsoleWrite(@error & @CRLF)
return $ret[0]
EndFunc
Func SuspendThread($hThread)
Local $ret = DllCall("kernel32.dll", "DWORD", "ResumeThread", "DWORD", $hThread)
; ConsoleWrite(@error & @CRLF)
return $ret[0]
EndFunc
; ---------------------------------------------------------------
Func SinThread($Sin)
Local $busySpan[$COUNT]
Local $idleSpan[$Count]
Local $half = INT($INTERVAL / 2)
Local $Rad = 0.0
Local $startTime
Local $i = 0
For $i=0 to $COUNT-1
$busySpan[$i] = INT($half * (1.0 + sin($PI * $rad) ))
$idleSpan[$i] = INT($half - $busySpan[$i])
$rad += $Split
Next
While 1
$i = Mod($i, $Count)
$startTime = GetTickCount()
while( GetTickCount() - $startTime <= $busySpan[$i])
WEnd
Sleep($idleSpan[$i])
$i+=1
WEnd
return 0
EndFunc
; ---------------------------------------------------------------
Func SawThread($Saw)
Local $busySpan[$COUNT]
Local $idleSpan[$Count]
Local $half = INT($INTERVAL / 2)
Local $Rad = 0.0
Local $startTime
Local $i = 0
For $i=0 to $COUNT-1
$busySpan[$i] = INT($SLOPE*$Rad)
$idleSpan[$i] = INT($INTERVAL - $busySpan[$i])
$rad += $Split
Next
While 1
$i = Mod($i, $Count)
$startTime = GetTickCount()
while( GetTickCount() - $startTime <= $busySpan[$i])
WEnd
Sleep($idleSpan[$i])
$i+=1
WEnd
return 0
EndFunc
; ---------------------------------------------------------------
; Main Function
Func Main()
; Dim $dwThread1, $dwThread2
Dim $hThread1, $hThread2
$hThread1 = CreateThread("SinThread")
$hThread2 = CreateThread("SawThread")
SetThreadAffinityMask($hThread1, 1)
SetThreadAffinityMask($hThread2, 2)
ResumeThread($hThread1)
ResumeThread($hThread2)
SuspendThread(GetCurrentThread())
While 1
; Sleep(16) ; Slic Time Of Windows = 15.75 ms
; Sleep(1) ; Slic Time Of Windows = 15.75 ms
WEnd
Return 0
EndFunc
以上,謝謝各位不吝賜教,小弟先行感激。 |