Creating a thread with the async CREATEOBJECT("ThreadManager")

Topics: User Forum
Feb 27, 2012 at 10:13 PM

I managed to make it work with path to files hard coded,

Trying to pass value with a FORM but when i create my object CREATEOBJECT("ThreadManager") i'm losing the FORM variable passed.

I tried storing the variable to a cookie but then again i lose the stored variable too.

Could somebody point me to a solution

Thanks

Andre

Coordinator
Feb 28, 2012 at 7:19 AM
Edited Feb 28, 2012 at 7:26 AM

You should be passing form variables to the background program as parameters.  From the mythreadfunc.prg demo:

-------------------------------------

 

LPARAMETERS P2   && p2 is the 2nd param to this background task (the first param is the prog name that will be run)

ALINES(larr,P2,.F.,",")  && parse comma delim string to get all params passed - larr contains passed variables

...
----------------------------


So cEventID=oAsync.CreateThread("mythreadfunc","MySecondParam1,MySecondParam2") &&MyThreadFunc is the prg that contains the code for the background task
Feb 28, 2012 at 9:31 PM

Thank you Claude,

i took a look at all the source code available and your response and re-did my code in my version of the mythreadfunc.prg

I understand the parameter P2 now.

I tried my code with the path to my file hard coded to make sure that all is well before, now i'm back to my variable problem

i'm not sure if it's in the way that i'm calling the thread

page1.avfp as the form that the user fills out "INPUT TEXT name FileSelected", on form METHOD="POST" ACTION="page2.avfp"

in the page2.avfp that's where i'm calling the CreateThread("mythreadfunc","trying to access FileSelected ")

I got the debug window on, as soon as the page2.avfp comes up my process starts but the Form Variable are not coming through

am i doing this the right way

Thanks

Coordinator
Feb 28, 2012 at 9:59 PM
Edited Feb 28, 2012 at 10:02 PM

No, these are two separate threads entirely so debugging probably is not going to work.  

First, you just have to make sure it's firing the background thread.  Does the background thread demo work correctly on your machine??  You will know it works if it says "Starting..." "25% Done" "50% Done" etc.  just like here:  http://thetechconsult.com/demo/default.aspx?action=thread

If you are NOT getting the "Starting...", etc on your machine, then the basic stuff is not working at all.  In this case, you'd probably just be better off using ParallelFox in VFPx instead than figuring out what's wrong.  (DEP, if it's on your machine, will prevent my Async class code from working)

On the other hand, if the demo is working properly, it should be easy to test with passing a parameter like:

cEventID=oAsync.CreateThread("mythreadfunc","MySecondParam1,MySecondParam2")

Just check and see if a parmeter is being passed with strtofile or something.
Feb 29, 2012 at 2:19 PM

Thank you for your time Claude,

Yes it's working, i changed the events.dbf field action from C(50) to a Memo field, this way i got to trace my program and see where it was hanging.

All the process is executing correctly from start to end.

My difficulty is in passing the value of <%=oRequest.Form("FileSelected")%> filled out in page1.avfp, it's passing .NULL., i think it's because of the creation of the oAsync=CREATEOBJECT("ThreadManager").

If i take out the creation of the "oAsync", the <%=oRequest.Form("FileSelected")%> return me the FileSelected from the previous page1.

My basic idea was to let a user select a file in page1, launch the long process thread with the file selected on page2 and give feed back, when all done bring them to another page. Hope it makes sense

Here is part of my code from page1 and page2

Page1
<form METHOD="POST" NAME="IMPORTDATA" ENCTYPE="multipart/form-data" ACTION="<%=JustPath(oProp.ScriptPath)+[/testing2]+oProp.Ext%>">
    &nbsp;Sélectionner le fichier à importer :</br>
    &nbsp;<input type="file" id="idFichier" name="fichier" onChange="javascript:showpath()" class="hide"/></br>
    &nbsp;<input type="text" id="idFileSelected" name="FileSelected" size=100/>
    <p>
    <input TYPE="SUBMIT" VALUE="Upload!"> <font face="Arial"><b><font face size="4"><small><font face="arial,helvetica">
    <input type="button" value="Go Back" onClick="history.back()"></font></small></font></b></font>
    </p>
                
</form>


page2
File Name and Path: <%=oRequest.Form("FileSelected")%>
THIS IS .NULL. ON PAGE LOADING WITH THE DEBUG WINDOW ON

<!-- ******************************************** -->
<%
        oAsync=CREATEOBJECT("ThreadManager")
.... the rest is the same as thread.avfp

   cEventID=oAsync.CreateThread("mythreadfunc") &&MyThreadFunc is the prg that contains the code for the background task
   ENDCASE
%>
<%=cMeta%>
      
 Async Processing&nbsp;Use real threads for background tasks from the web
 &lt;%=cCancel%&gt;</br>
 &lt;%=cMess%&gt;

Thank you

André
Coordinator
Feb 29, 2012 at 11:12 PM

Yeah, it looks like if you pass a parameter then it doesn't start the background process.  So there is an error in there probably, in CreateThread in webthreads.prg.   What it does is append any parameter that is passed in to a unique ID that occupies the first parameter position.  My guess is that I'm not formatting that string properly when I append it and it bombs at the next step.  I'll debug this tonight and see if I can come up with a fix.

Coordinator
Mar 2, 2012 at 8:48 PM

Fix this line in Webthreads.prg

ThreadProcParam = IIF(EMPTY(ThreadProcParam),SUBSTR(SYS(2015),3,10),SUBSTR(SYS(2015),3,10)+[,]+ThreadProcParam)

to contain the passed in parameter and I think it will work. 

 

I think I messed it up by not putting in quotes or something.  I'll leave it up to you because I don't have any time...

Mar 2, 2012 at 9:06 PM

OK i'll give it a go,

i'm off for the next week but will test this first thing when i'm back and will give you feedback.

Thank you for your time, much appreciated.

Love your work and will be using it actively.

Mar 12, 2012 at 8:23 PM

Hello Claude,

i'm taking a look at the code in Webthreads.prg and i downloaded all that could be downloaded from this site "DOWNLOADS" and "SOURCE CODE" (all version) to search for the following

ThreadProc.fxp or .prg and i cannot find it

IF !FILE(oProp.AppStartPath+"prg\"+ThreadProc+".fxp") && must be compiled object
  COMPILE oProp.AppStartPath+"prg\"+ThreadProc+".prg"
ENDIF

 

Could you tell me where it is please

Thank you

André

Mar 14, 2012 at 9:04 PM

Well, ok i made some progress, but back to square one.

 

My difficulty is in passing the value of <%=oRequest.Form("FileSelected")%> filled out in page1.avfp, 
it's passing .NULL., i think it's because of the creation of the oAsync=CREATEOBJECT("ThreadManager").

 

 

I found the ThreadProc, it's a reference to the program that's been called :

mythreadfunc

so i changed the events table to catch variables content my_debug M(4).

Added in the CreateThread

 

lcDebugOut = ;
"TYPE(" + VARTYPE((ThreadProc)) + ") " + ALLTRIM(TRANSFORM(ThreadProc)) + CHR(13) + ;
 "TYPE(" + VARTYPE((ThreadProcParam)) + ") " + ALLTRIM(TRANSFORM(ThreadProcParam)) + CHR(13) + ;
 "TYPE(" + VARTYPE((cDoneCmd)) + ") " + ALLTRIM(TRANSFORM(cDoneCmd)) + CHR(13) + ;
 "TYPE(" + VARTYPE((cProcCmd)) + ") " + ALLTRIM(TRANSFORM(cProcCmd)) + CHR(13) + ;
 "check fxp = " + IIF( FILE(oProp.AppStartPath+"prg\"+ThreadProc+".fxp") , "PRESENT" , "NOT PRESENT")

 

REPLACE my_debug WITH ALLTRIM(my_debug) + CHR(13) + REPLICATE("-",20) + CHR(13) + (lcDebugOut)

so i get --------------------
TYPE(C) mythreadfunc
TYPE(L) .F.
TYPE(L) .F.
TYPE(L) .F.
check fxp = PRESENT

I then added in the INIT of the CLASS ThreadManager

lcEventFile=oProp.AppStartPath+'temp\events.DBF'
IF ! USED('events')
	USE (lcEventFile) IN 0 SHARED
ENDIF
SELECT events
APPEND BLANK
REPLACE my_debug WITH oRequest.Form("FileSelected")
USE

oRequest.Form("FileSelected") return .NULL. again

so CREATEOBJECT("ThreadManager"), gives me .NULL. even before the ThreadProc()

I am going to continue this, just hoping that somebody could give me a clue

Thanks
André
Mar 19, 2012 at 4:51 PM

Finally found it.

Having the creation of the object CREATEOBJECT("ThreadManager")
on the same page .avfp as the creation of the cookie.Value or oSession.Value is not good.

I created a page to catch the value i wanted to store to either Session.value or cookie.Value,
added a button to launch the other page that will launch the ThreadProc.

Now my oSession.Value is there and the launch of the thread works correctly with parameters

cEventID=oAsync.CreateThread("mythreadfunc",oSession.Value("FileSelected"))

In the prg "mythreadfunc", decompose the array to reassign value

ALINES(larr,P2,.F.,",")  && parse comma delim string to get all params passed
P2 = larr(1) && holds the asyncID in first position of array, it needs to be re-assigned to P2 as String, not array
secP2 = larr(2) && That's the content of the second parameter passed : oSession.Value("FileSelected")

Hope this will help somebody else

André

Coordinator
Mar 19, 2012 at 8:09 PM

Excellent!  Thanks for seeing this problem all the way through to a solution!!

Coordinator
Apr 23, 2012 at 8:52 AM

I'll make sure the CreateThread example passes parameters in the next version of AVFP.  Passing parameters, of course, makes CreateThread much more useful..