Sign in to follow this  
Followers 0
michaelslamet

While-WEnd Question

37 posts in this topic

#1 ·  Posted (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 by michaelslamet

Share this post


Link to post
Share on other sites



Don't use sleep to determine differences between times. Use better Timer.


Best Regards BugFix  

Share this post


Link to post
Share on other sites

Don't use sleep to determine differences between times. Use better Timer.

 

How can I use this in my case?

Share this post


Link to post
Share on other sites

Try this:

Func SleepUntilCanAccess ($ShouldPassHowManyMiliSecs_Param = 200)
    ; ...
    $timer = TimerInit()
    While TimerDiff($timer) < $ShouldPassHowManyMiliSecs_Param
        ; ...
        ; ...
    WEnd
    ; ...
EndFunc

Best Regards BugFix  

Share this post


Link to post
Share on other sites

Thank you, BugFix :)

I'm gonna to try it, but I cant see how that can make much difference (?)

Share this post


Link to post
Share on other sites

#6 ·  Posted (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 by AutID

Share this post


Link to post
Share on other sites

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.


_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_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 parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 04/09/2015

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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 Gude
How 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

Share this post


Link to post
Share on other sites

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?

Share this post


Link to post
Share on other sites

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!

Share this post


Link to post
Share on other sites

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 :)

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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?

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0