another tip to avoid crashes with strings and threads

Share your advanced PureBasic knowledge/code with the community.
User avatar
Rings
Moderator
Moderator
Posts: 1435
Joined: Sat Apr 26, 2003 1:11 am

another tip to avoid crashes with strings and threads

Post by Rings »

Code updated For 5.20+

DIGE asks about Critical sections in IRC , and i did a small code to use them to avoid crashes from multilply use of strings in Threads
This snippet only works under windows, remember that in the section of entercriticalsection and Leavecriticalsection no other threads have access to the strings :) (they have to wait)

Code: Select all

Global CSInitialized.l
Global CS.CRITICAL_SECTION
 
Global A.s
 
Procedure testme(P)
If CSInitialized =0
 InitializeCriticalSection_(CS)
 CSInitialized = 1
EndIf
 
While T<20
EntercriticalSection_(Cs)
;do everything now 
A.s=Str(p)
Debug A.s
LeaveCriticalSection_(CS)
Delay(500)
T+1
Wend
EndProcedure
 
For I=1 To 10
 ThreadID = CreateThread(@testme(), I) 
Next I
 
Max=10000
t0=GetTickcount_()
While t<Max
 t=GetTickcount_()-T0
 Delay(100)
 A.s="0"
 Debug A.s
Wend
SPAMINATOR NR.1
newbie
Enthusiast
Enthusiast
Posts: 296
Joined: Tue Jul 29, 2003 5:47 pm
Location: FRANCE
Contact:

Post by newbie »

Nice to know, I didn't know this API ;)
- Registered PB user -

Using PB 4.00
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: another tip to avoid crashes with strings and threads

Post by PB »

What exactly is the story with threads and strings? I've used strings in threads
for ages with no problems. What is the problem? And does wrapping a thread
with EnterCriticalSection and LeaveCriticalSection make them safer? If so,
shouldn't Fred automatically use these APIs in the compiled thread code?
dmoc
Enthusiast
Enthusiast
Posts: 739
Joined: Sat Apr 26, 2003 12:40 am

Post by dmoc »

I've used strings in threads for ages with no problems.
...you have just been lucky. Eventually your code will crash and burn :twisted:
newbie
Enthusiast
Enthusiast
Posts: 296
Joined: Tue Jul 29, 2003 5:47 pm
Location: FRANCE
Contact:

Post by newbie »

I have finally needed it :P

Without this method, strings to display get overlapped like :

"local" + "remote" displays "loremote"

now everything works fine ;)
- Registered PB user -

Using PB 4.00
newbie
Enthusiast
Enthusiast
Posts: 296
Joined: Tue Jul 29, 2003 5:47 pm
Location: FRANCE
Contact:

Post by newbie »

Works better with Mutex :

Mutex creation :

Code: Select all

HLog   = CreateMutex_(#Null, 0, "ZoneLog")

If Hlog = #Null
MessageBox_(0, "Error while creating Mutex.", "MyProg :", #MB_ICONERROR)
End
endif
Mutex usage :

Code: Select all

res = OpenMutex_(#MUTEX_ALL_ACCESS, 0, "ZoneLog")
    While res = #Null : res = OpenMutex_(#MUTEX_ALL_ACCESS, 0, "ZoneLog") : Wend

; your code here

ReleaseMutex_(res)
CloseHandle_(res)   
If I don't do it right, feel free to correct me ;)
- Registered PB user -

Using PB 4.00
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

EnterCriticalSection_() is fine for simple thread-safety... When your programs use a large number of threads and shared memory, it is very important not to lock every thread each time something needs to be accessed... This will bring your program to a slooooooow crawl... I agree with newbie... Mutex_() is a better practice...
User avatar
Rings
Moderator
Moderator
Posts: 1435
Joined: Sat Apr 26, 2003 1:11 am

Post by Rings »

PolyVector wrote:EnterCriticalSection_() is fine for simple thread-safety... When your programs use a large number of threads and shared memory, it is very important not to lock every thread each time something needs to be accessed... This will bring your program to a slooooooow crawl... I agree with newbie... Mutex_() is a better practice...
of course you should not lock complete Threads(Procedures), only critical sections like String-Operations.
SPAMINATOR NR.1
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

I only meant that complex multi-threaded apps need to be very carefull with mutal-exclusion syncronization... The mutex object provies much more control with commands like WaitForSingleObject_()...
Critical Sections are somewhat limited... In a large project, you might run into problems w/ thread lock...

I'm very tired, maybe I'm not making sense... Just ignore me :|
newbie
Enthusiast
Enthusiast
Posts: 296
Joined: Tue Jul 29, 2003 5:47 pm
Location: FRANCE
Contact:

Post by newbie »

my previous code was wrong, here a right one, and with 3 Mutex :

create the needed Mutex first

Code: Select all

#WAIT_OBJECT_0 = $0

Global HLog
Global HEnter
Global HChat

HLog   = CreateMutex_(#Null, 0, "ZoneLog")
HEnter = CreateMutex_(#Null, 0, "ZoneEnter")
HChat  = CreateMutex_(#Null, 0, "ZoneChat")
let's say they refer to different gadget from a GUI, that many threads access to modify.

If a thread need access and need to ensure that it will have exclusive access,
you can do this :

Code: Select all

Dim hArray.l(2)
hArray(0) = HChat
hArray(1) = HLog
hArray(2) = HEnter

;Wait maximum 5s until the 3 Mutex are free for ownership    
res = WaitForMultipleObjects_(3, @hArray(0), 1, 5000) 
If res = #WAIT_OBJECT_0
 ;your code here
 ;don't forget to release the Mutex for the other Threads !!
    ReleaseMutex_(HLog)
    ReleaseMutex_(HChat)
    ReleaseMutex_(HEnter)
endif
You can use WaitForSingleObject instead for only one Mutex.
- Registered PB user -

Using PB 4.00
newbie
Enthusiast
Enthusiast
Posts: 296
Joined: Tue Jul 29, 2003 5:47 pm
Location: FRANCE
Contact:

Post by newbie »

Hi,

can someone elaborate about this from the help file ?
Note: Threads need to be used carefully because it is possible that you can have multiple access to shared resources (memory, variables, files, etc) and you need to manually ensure that you do run into trouble because of this. For example, it is not safe to modify or write to strings from more than one thread because strings share the same internal memory buffer. If you only ever read from strings while your threads are running then it should be safe.

If you still want to modify strings safely in threads (or any other shared access resource), you need to make sure that only one thread can use strings at a time. To do this you should make use of the synchronisation capabilities of the OS you are running on.
I thought it was just like the Ring example, about a Global string variable, but after reading the help, It makes me wonder if it means that just one thread at a time can write to any local string, because even the local strings are sharing the same global buffer space ??
I mean that two Threads can't do string operation even if the string variables are locals to these Threads ?

Is two threads can simultaneously do memory operation like CopyMemory
if the variables involved are only local to these threads ?

I hope my question makes sense.
- Registered PB user -

Using PB 4.00
freedimension
Enthusiast
Enthusiast
Posts: 613
Joined: Tue May 06, 2003 2:50 pm
Location: Germany
Contact:

Post by freedimension »

PB String Functions do indeed use the same String Buffer for running. For more information have a look in the PB SDK Documentation.

But I don't know if even the simple String Concatenation str1$ + str2$ uses this Buffer!?
User avatar
Rings
Moderator
Moderator
Posts: 1435
Joined: Sat Apr 26, 2003 1:11 am

Post by Rings »

freedimension wrote:PB String Functions do indeed use the same String Buffer for running. For more information have a look in the PB SDK Documentation.

But I don't know if even the simple String Concatenation str1$ + str2$ uses this Buffer!?
it does afaik
SPAMINATOR NR.1
Fred
Administrator
Administrator
Posts: 18254
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

Yes, it uses it. The Enter/LeaveCriticalSection is a good way to enable string safe threads. It uses a mutex under the hood so it's there is no drawback to use it instead mutex for simple synchronisation.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

> it is not safe to modify or write to strings from more than one thread

Does this mean if my app has only one thread (created with CreateThread)
that it's safe to modify strings inside it? Or does the rest of my app (outside
of this thread) also count as a thread? I'm confused.
Post Reply