String problem when starting thread from a procedure

Just starting out? Need help? Post your questions and find answers here.
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

String problem when starting thread from a procedure

Post by Dude »

This works fine:

Code: Select all

; Unicode ON
; Threadsafe ON

Procedure MyThread(name)
  Debug PeekS(name) ; Shows 123
EndProcedure

var$="123"
CreateThread(@MyThread(),@var$)

Repeat
  Delay(1)
ForEver
But this shows gibberish for the debug output:

Code: Select all

; Unicode ON
; Threadsafe ON

Procedure MyThread(name)
  Debug PeekS(name) ; Shows gibberish
EndProcedure

Procedure StartThread(var$)
  CreateThread(@MyThread(),@var$)
EndProcedure

StartThread("123")

Repeat
  Delay(1)
ForEver
The only difference is starting the thread from inside a procedure, but the manual doesn't say that can't be done.

As a side-note, if I change the StartThread() procedure to a macro, it works fine. So the procedure is the problem.
DontTalkToMe
Enthusiast
Enthusiast
Posts: 334
Joined: Mon Feb 04, 2013 5:28 pm

Re: String problem when starting thread from a procedure

Post by DontTalkToMe »

No bug, code is wrong :wink: : variable goes out of scope before thread could start.

Try to put a Delay(1000) after CreateThread(@MyThread(),@var$) and see what happens.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8433
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: String problem when starting thread from a procedure

Post by netmaestro »

Just change the single line you have to this:

Code: Select all

Threaded var$
StartThread("123")
and Bob's still someone else's uncle but you're starting to get there...
BERESHEIT
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: String problem when starting thread from a procedure

Post by Dude »

DontTalkToMe wrote:variable goes out of scope before thread could start.
What does that mean? Adding the delay fixes it, sure; but why? I'm passing the variable to the thread as a parameter, so why isn't it accepting it?

Code: Select all

Threaded var$
Doesn't make any difference here; still gibberish. :?:
infratec
Always Here
Always Here
Posts: 6869
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: String problem when starting thread from a procedure

Post by infratec »

Hi,

you didn't fully understand what you are doing.

The parameter of the thread is a pointer. That's clear.
You call the thread from a procedure with the address of the procedure parameter.
But the procedure is not waiting for the end of the thread and when
the procedure is finished, the parameter of the procedure does not exist any longer.
So the thread parameter points then to ... nothing.

It depends if the thread reaches first the peeks() or if the procedure is first finished.

All in all: it is a bug from your code.

I hope it's clear now what happens.

The only way to avoid this:

Code: Select all

Procedure MyThread(name)
  Debug PeekS(name) ; Shows gibberish
EndProcedure

Procedure StartThread(var$)
  
  Static String$
  
  String$ = var$
  
  CreateThread(@MyThread(),@String$)
EndProcedure

StartThread("123")
Debug "StartThread finished"

Repeat
  Delay(1)
ForEver
Bernd
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: String problem when starting thread from a procedure

Post by Dude »

The StartThread() procedure is designed to exit after starting the thread; it's not intended to stay alive or wait for anything. It's sole job is just a way for me to start the thread from one of several different methods (mouse click, hotkey, or other) at any given time, without needing to have the same procedure code several times in my app (because the procedure has a bit more code to it, that I didn't post in this example).

Anyway, Delay(100) solves the problem, so I may as well just do that... even though I admit I still don't understand the issue. Are you saying that by the time MyThread(name) has started, that "name" is now null before PeekS() can get to it? It's all just a timing issue? PureBasic is really that fast? :shock: :lol:
infratec
Always Here
Always Here
Posts: 6869
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: String problem when starting thread from a procedure

Post by infratec »

Try this and you see who is faster:

Code: Select all

Procedure MyThread(name)
  Debug "Before PeekS()"
  Debug PeekS(name) ; Shows gibberish
EndProcedure

Procedure StartThread(var$)
  CreateThread(@MyThread(),@var$)
EndProcedure

StartThread("123")
Debug "StartThread finished var$ not longer available"

Repeat
  Delay(1)
ForEver
With my 'Static' variable I avoid that the variable is released at the end of the procedure.

Bernd
User avatar
mhs
Enthusiast
Enthusiast
Posts: 101
Joined: Thu Jul 02, 2015 4:53 pm
Location: Germany
Contact:

Re: String problem when starting thread from a procedure

Post by mhs »

Yes it's a timing issue in your case.

It's like the others say: The procedure StartThread is finished before the thread is initialised and started. After StartThread has ended the variable name is invalid and so PeekS accesses an invalid memory...
DontTalkToMe
Enthusiast
Enthusiast
Posts: 334
Joined: Mon Feb 04, 2013 5:28 pm

Re: String problem when starting thread from a procedure

Post by DontTalkToMe »

Dude wrote:I'm passing the variable to the thread as a parameter, so why isn't it accepting it?
You are passing the address of the variable, not a copy of the variable.
After you started a new thread your procedure continue its execution and then terminates very quickly since there is no more code after your CreateThread().
When the procedure terminates, the local variable var$ is deallocated.
At this point its old address, the one you passed to the thread, points to garbage.

The new thread in the meantime is starting and then executes a peek on the invalid address you passed.

Now you should understand why the Delay() fixes the problem.

The variable class needs to be static (so Global or Static, both are static) to be still there for when you try to access it, or you need to wait for the thread to end with WaitThread() before leaving the procedure. The Delay() was an approximation of WaitThread() in this case.
acreis
Enthusiast
Enthusiast
Posts: 182
Joined: Fri Jun 01, 2012 12:20 am

Re: String problem when starting thread from a procedure

Post by acreis »

Try this:

Code: Select all


; Unicode ON
; Threadsafe ON

Procedure MyThread(name)
  Debug PeekS(name) ; Shows gibberish
EndProcedure

Procedure StartThread(var$)
  MessageRequester("Caution", "You are going o pass the address of 'var$' To a Thread!" + Chr(13) +
  "Var$ value only exists while StartThread doesn't end!")
  
  CreateThread(@MyThread(),@var$)
  Debug "StartThread() is ending, so 'var$' doesn't exist anymore!"
  Debug "If you try use it, you will get gibberish!"
  Debug "_______________________"
  
EndProcedure

StartThread("123")

Debug "Ok! I said you could't use 'var$' ..."

Delay(4000)

Debug "_______________________"

Debug "Doing the right thing:"

Global gVar$ ;<- this variable will remain valid till the End

Procedure gStartThread(var$)
  
  gVar$ = var$
  
  CreateThread(@MyThread(),@gvar$)
  
EndProcedure

gStartThread("123")

Delay(10000)


End
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: String problem when starting thread from a procedure

Post by Dude »

Thanks everyone! :) I understand the problem now.
User avatar
mhs
Enthusiast
Enthusiast
Posts: 101
Joined: Thu Jul 02, 2015 4:53 pm
Location: Germany
Contact:

Re: String problem when starting thread from a procedure

Post by mhs »

Another solution for using StartThread multiple times:

Code: Select all

Procedure MyThread(*name)

  Debug PeekS(*name) ; Shows gibberish
  
  FreeMemory(*name)
  
EndProcedure

Procedure StartThread(var$)
 
  Define *mem

  *mem = AllocateMemory(StringByteLength(var$) + 2)
  PokeS(*mem, var$)
 
  CreateThread(@MyThread(), *mem)
  
EndProcedure

StartThread("123")
StartThread("456")
StartThread("789")

Debug "StartThread finished"

Repeat
  Delay(1)
ForEver
User avatar
bgeraghty
User
User
Posts: 52
Joined: Wed Apr 02, 2014 12:45 am
Location: irc.ibotched.it:+6697
Contact:

Re: String problem when starting thread from a procedure

Post by bgeraghty »

Since it seems to be a timing issue which may differ from machine to machine, why not actually wait for the thread to be valid before exit? :

Code: Select all

Procedure ThreadProc(*Text)
  Protected Variable$ = PeekS(*Text)
  Debug Variable$
EndProcedure

Procedure Main()
  Var$ = "Hello From PB!"
  TheThread = CreateThread(@ThreadProc(), @Var$)
  While Not IsThread(TheThread)
    Delay(10)
  Wend
EndProcedure
SolveMyIssue_() - No QuickHelp available.
User avatar
mk-soft
Always Here
Always Here
Posts: 5393
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: String problem when starting thread from a procedure

Post by mk-soft »

I think the best way is over a structure of data...

Code: Select all


Structure udtData
  ThreadID.i
  Exit.i
  Text.s
  Result.i
EndStructure

Global thData.udtData

Procedure ThreadProc(*Data.udtData)
  Protected Variable$
  
  With *Data
    Variable$ = \Text
    Debug Variable$
    Repeat
      Debug "Working..."
      Delay(500)
    Until \Exit 
  EndWith
EndProcedure

Procedure Main()
  
  thData\Text = "Hello From PB!"
  thData\ThreadID = CreateThread(@ThreadProc(), thData)
  Delay(5000)
  thData\Exit = 1
  
  While Not IsThread(thData\ThreadID)
    Delay(10)
  Wend
EndProcedure : Main()
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Post Reply