michaelslamet Posted December 16, 2013 Posted December 16, 2013 (edited) My script run by many users on a network drive. Before it run a particular function, the script need to make sure that this function is only run only 1 time in the last 200 miliseconds. Example: Script at PC-A run this function at hour 12:00:05.190 then Script at PC-B can not run this function before 12:00:05.390 So when there is a request, it should sleep until it pass the 200ms. So I keep a record "which PC run this function and when" into a MySQL database on a server. No problem on this part. I also have no problem on finding a milisecond different between current time and last record on the database. My only problem is sometime my routine that "sleep until 200ms passed" fail. Example, this is a database record: 1--> 12:00:05.190 2--> 12:00:05.590 3--> 12:00:05.690 As we can see, between second and third row, the delay is only 100ms. Third row/record is created because my routine think it's now pass the 200ms delay because IT'S USING FIRST RECORD AS REFERENCE! What it dont know is while it's sleeping waiting the 200ms to pass, another PC run this function (so the second record is created). This is my code: SleepUntilCanAccess (200) Run_this_special_function_that_will_error_if_accessed_more_than_once_in_200_ms() ; only need few miliseconds for this function to finish WriteLogToDatabase() SleepUntilCanAccess (200) Func SleepUntilCanAccess ($ShouldPassHowManyMiliSecs_Param = 200) Local $current_time_local, $last_time_in_database Local $date_diff_local Local $tmp = 0 While $tmp < $ShouldPassHowManyMiliSecs_Param $current_time_local = StringSplit(@YEAR & ":" & @MON & ":" & @MDAY & ":" & @HOUR & ":" & @MIN & ":" & @SEC & "." & @MSEC, ":") _ArrayDelete($current_time_local, 0) ; delete first element of the array $last_time_in_database_local = StringSplit(ReadLastDateFromLogDatabase(), ":") _ArrayDelete($last_time_in_database_local, 0) ; delete first element of the array $date_diff_local = _DateDiff_2($last_time_in_database_local, $current_time_local) If $date_diff_local[0] > 0 OR $date_diff_local[1] > 0 OR $date_diff_local[2] > 0 OR $date_diff_local[3] > 0 OR $date_diff_local[4] > 0 Then ; if date_diff return more than 1 min ExitLoop Else $tmp = $date_diff_local[5] * 1000 ; convert to milisecond Sleep($ShouldPassHowManyMiliSecs_Param) EndIf WEnd Return EndFunc My only thinking for now is before exit the routine, it should check if the reference is THE LAST RECORD? Please advice me. Thanks you Edited December 16, 2013 by michaelslamet
BugFix Posted December 16, 2013 Posted December 16, 2013 Don't use sleep to determine differences between times. Use better Timer. Best Regards BugFix
michaelslamet Posted December 16, 2013 Author Posted December 16, 2013 Don't use sleep to determine differences between times. Use better Timer. How can I use this in my case?
BugFix Posted December 16, 2013 Posted December 16, 2013 Try this: Func SleepUntilCanAccess ($ShouldPassHowManyMiliSecs_Param = 200) ; ... $timer = TimerInit() While TimerDiff($timer) < $ShouldPassHowManyMiliSecs_Param ; ... ; ... WEnd ; ... EndFunc Best Regards BugFix
michaelslamet Posted December 16, 2013 Author Posted December 16, 2013 Thank you, BugFix I'm gonna to try it, but I cant see how that can make much difference (?)
AutID Posted December 16, 2013 Posted December 16, 2013 (edited) I understand nothing from you example. And you have imaginary functions thats dont allow us to test it. If you want to sleep for 200 miliseconds this will work for you. Local $timer = TimerInit() Local $time = _SleepUntilCanAccess(200) ;ConsoleWrite($time & @LF) Comment out these 2 lines if you want to see the time in miliseconds Func _SleepUntilCanAccess($SleepTime) Do Local $r = Round(TimerDiff($timer), 1) Sleep(10) Until $r > $SleepTime ;Return $r Comment out these 2 lines if you want to see the time in miliseconds EndFunc Comment out the 2 lines if you want to return the miliseconds. Then you can use your imaginary functions to compare the last time with the time passed returned from this function. Edited December 16, 2013 by AutID https://iblockify.wordpress.com/
guinness Posted December 16, 2013 Posted December 16, 2013 Surely $timer should be declared as Global and not Local. I know people will tell me but Local outside of a function is Global, but I see this as being a bug of some sorts. UDF List: _AdapterConnections() • _AlwaysRun() • _AppMon() • _AppMonEx() • _ArrayFilter/_ArrayReduce • _BinaryBin() • _CheckMsgBox() • _CmdLineRaw() • _ContextMenu() • _ConvertLHWebColor()/_ConvertSHWebColor() • _DesktopDimensions() • _DisplayPassword() • _DotNet_Load()/_DotNet_Unload() • _Fibonacci() • _FileCompare() • _FileCompareContents() • _FileNameByHandle() • _FilePrefix/SRE() • _FindInFile() • _GetBackgroundColor()/_SetBackgroundColor() • _GetConrolID() • _GetCtrlClass() • _GetDirectoryFormat() • _GetDriveMediaType() • _GetFilename()/_GetFilenameExt() • _GetHardwareID() • _GetIP() • _GetIP_Country() • _GetOSLanguage() • _GetSavedSource() • _GetStringSize() • _GetSystemPaths() • _GetURLImage() • _GIFImage() • _GoogleWeather() • _GUICtrlCreateGroup() • _GUICtrlListBox_CreateArray() • _GUICtrlListView_CreateArray() • _GUICtrlListView_SaveCSV() • _GUICtrlListView_SaveHTML() • _GUICtrlListView_SaveTxt() • _GUICtrlListView_SaveXML() • _GUICtrlMenu_Recent() • _GUICtrlMenu_SetItemImage() • _GUICtrlTreeView_CreateArray() • _GUIDisable() • _GUIImageList_SetIconFromHandle() • _GUIRegisterMsg() • _GUISetIcon() • _Icon_Clear()/_Icon_Set() • _IdleTime() • _InetGet() • _InetGetGUI() • _InetGetProgress() • _IPDetails() • _IsFileOlder() • _IsGUID() • _IsHex() • _IsPalindrome() • _IsRegKey() • _IsStringRegExp() • _IsSystemDrive() • _IsUPX() • _IsValidType() • _IsWebColor() • _Language() • _Log() • _MicrosoftInternetConnectivity() • _MSDNDataType() • _PathFull/GetRelative/Split() • _PathSplitEx() • _PrintFromArray() • _ProgressSetMarquee() • _ReDim() • _RockPaperScissors()/_RockPaperScissorsLizardSpock() • _ScrollingCredits • _SelfDelete() • _SelfRename() • _SelfUpdate() • _SendTo() • _ShellAll() • _ShellFile() • _ShellFolder() • _SingletonHWID() • _SingletonPID() • _Startup() • _StringCompact() • _StringIsValid() • _StringRegExpMetaCharacters() • _StringReplaceWholeWord() • _StringStripChars() • _Temperature() • _TrialPeriod() • _UKToUSDate()/_USToUKDate() • _WinAPI_Create_CTL_CODE() • _WinAPI_CreateGUID() • _WMIDateStringToDate()/_DateToWMIDateString() • Au3 script parsing • AutoIt Search • AutoIt3 Portable • AutoIt3WrapperToPragma • AutoItWinGetTitle()/AutoItWinSetTitle() • Coding • DirToHTML5 • FileInstallr • FileReadLastChars() • GeoIP database • GUI - Only Close Button • GUI Examples • GUICtrlDeleteImage() • GUICtrlGetBkColor() • GUICtrlGetStyle() • GUIEvents • GUIGetBkColor() • Int_Parse() & Int_TryParse() • IsISBN() • LockFile() • Mapping CtrlIDs • OOP in AutoIt • ParseHeadersToSciTE() • PasswordValid • PasteBin • Posts Per Day • PreExpand • Protect Globals • Queue() • Resource Update • ResourcesEx • SciTE Jump • Settings INI • SHELLHOOK • Shunting-Yard • Signature Creator • Stack() • Stopwatch() • StringAddLF()/StringStripLF() • StringEOLToCRLF() • VSCROLL • WM_COPYDATA • More Examples... Updated: 22/04/2018
AutID Posted December 16, 2013 Posted December 16, 2013 Surely $timer should be declared as Global and not Local. I know people will tell me but Local outside of a function is Global, but I see this as being a bug of some sorts. Now that you mention it i have ran to that problem as well. And since local outside a function is global then why not declare it as global directly?!?! Didn't think about it... Good point. https://iblockify.wordpress.com/
markyrocks Posted December 16, 2013 Posted December 16, 2013 My only thought is that what if more than one pc attempts to run script almost simultaneously? Seems they would both be using the previous log entry but would return times within 200 milliseconds of each other? I could be completely wrong but it's an interesting thought. Spoiler "I Believe array math to be potentially fatal, I may be dying from array math poisoning"
JohnOne Posted December 16, 2013 Posted December 16, 2013 How exactly are your scripts communicating? AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans.
michaelslamet Posted December 16, 2013 Author Posted December 16, 2013 How exactly are your scripts communicating? They are not communicating each others. They only read the last record on the MySQL database server before call that particular function to make sure that function is only called (by any scripts) once in 200ms. Anyway, I think I can use this, but I need to test it tommorow at office. Below I make sure that the reference record has not been change. What do you think? SleepUntilCanAccess (200) Run_this_special_function_that_will_error_if_accessed_more_than_once_in_200_ms() ; only need few miliseconds for this function to finish WriteLogToDatabase() SleepUntilCanAccess (200) Func SleepUntilCanAccess ($ShouldPassHowManyMiliSecs_Param = 200) Local $current_time_local, $last_time_in_database Local $date_diff_local Local $tmp = 0 While 1 $current_time_local = StringSplit(@YEAR & ":" & @MON & ":" & @MDAY & ":" & @HOUR & ":" & @MIN & ":" & @SEC & "." & @MSEC, ":") _ArrayDelete($current_time_local, 0) ; delete first element of the array $last_log = ReadLastDateFromLogDatabase() $last_time_in_database_local = StringSplit($last_log, ":") _ArrayDelete($last_time_in_database_local, 0) ; delete first element of the array $date_diff_local = _DateDiff_2($last_time_in_database_local, $current_time_local) If ($date_diff_local[0] > 0 OR $date_diff_local[1] > 0 OR $date_diff_local[2] > 0 OR $date_diff_local[3] > 0 OR $date_diff_local[4] > 0) AND (ReadLastDateFromLogDatabase() = $last_log) Then ; ; if date_diff return more than 1 min ExitLoop Else $tmp = $date_diff_local[5] * 1000 If $tmp > $ShouldPassHowManyMiliSecs_Param AND ReadLastDateFromLogDatabase() = $last_log Then Return Else $tmp = 0 EndIf EndIf WEnd Return EndFunc
michaelslamet Posted December 16, 2013 Author Posted December 16, 2013 My only thought is that what if more than one pc attempts to run script almost simultaneously? Seems they would both be using the previous log entry but would return times within 200 milliseconds of each other? I could be completely wrong but it's an interesting thought. In fact, that is what currently happened: more than one pc attempts to run the script simultaneously. But this particular function is not called everytime the script run. I just called when user click a particular button.
markyrocks Posted December 16, 2013 Posted December 16, 2013 I'm almost thinking that if the function your referring to was saved on a separate .au3 file then you could just check to see if that process is running. If it is then wait till it doesn't exist plus 200ms. Spoiler "I Believe array math to be potentially fatal, I may be dying from array math poisoning"
JohnOne Posted December 16, 2013 Posted December 16, 2013 They are not communicating each others. They only read the last record on the MySQL database server before call that particular function to make sure that function is only called (by any scripts) once in 200ms. The problem here is that one script does not know if another is accessing the database. You could and probably will have multiple scripts accessing it at the same time. 2, 3 or 200 scripts check the database all withing 1 millisecond of each other, they see it has not been accessed for 200ms, they all access. With your current thinking you might get 2 scripts to obey your rules, 3 you're pushing your luck any more, you don't have a chance. I'd advise you devise a solution server side. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans.
BrewManNH Posted December 16, 2013 Posted December 16, 2013 Can't you lock the tables while one client is accessing it, then unlock it when it's done? If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays. - ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script. - Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label. - _FileGetProperty - Retrieve the properties of a file - SciTE Toolbar - A toolbar demo for use with the SciTE editor - GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI. - Latin Square password generator
michaelslamet Posted December 16, 2013 Author Posted December 16, 2013 The problem here is that one script does not know if another is accessing the database. You could and probably will have multiple scripts accessing it at the same time. 2, 3 or 200 scripts check the database all withing 1 millisecond of each other, they see it has not been accessed for 200ms, they all access. With your current thinking you might get 2 scripts to obey your rules, 3 you're pushing your luck any more, you don't have a chance. I'd advise you devise a solution server side. Yes, you're correct, I never think about this before By "server side solution" you mean the MySQL server?
michaelslamet Posted December 16, 2013 Author Posted December 16, 2013 Can't you lock the tables while one client is accessing it, then unlock it when it's done? Hey, this is a interesting idea! I have no idea now how to implement this and how is the logic, but I think this is one of the good solution!
michaelslamet Posted December 16, 2013 Author Posted December 16, 2013 I'm almost thinking that if the function your referring to was saved on a separate .au3 file then you could just check to see if that process is running. If it is then wait till it doesn't exist plus 200ms. No, it is not saved on a separate .au3 file and I dont think this is the issue
JohnOne Posted December 16, 2013 Posted December 16, 2013 If you can and do lock the table until one query is completed, alone, you could wind up with some clients getting greedy access while others get none or little. Probably need a queue control script on the server machine. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans.
michaelslamet Posted December 16, 2013 Author Posted December 16, 2013 If you can and do lock the table until one query is completed, alone, you could wind up with some clients getting greedy access while others get none or little. Probably need a queue control script on the server machine. Could you please explain more detail about the "queue control script on the server machine"? Which server? the MySQL server?
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now