CreateThread Procedure corrupting strings
Posted: Tue Jun 06, 2023 6:46 pm
I have a bit of confusion about strings, arrays, memory allocation, and threads. I can't post actual project code here, the situation is complex, so I'll try to simplify. I'm not looking for a magic fix, just wanted community thoughts about what I might be misunderstanding.
On program startup I create an array of structures. I wanted it global, but don't know at startup how many records I'll need so did it like this:
I am assuming that the Redim statement allocates enough memory upfront for all of the structures in the array. And, as I assign string values to all of them, that the string space is allocated as well. Are the String1 and String2 items in the record actually pointers to the externally allocated string buffers? I would think so. At any rate, I assume at this point that all of my array records, strings, etc, are all in safely allocated purebasic-managed memory spaces.
Later in the program I do some work, during which some new maps are created and used, etc. I want to pass it a single record from the array, so I've been doing it like this:
...my assumption above is that this is a good way to pass a the contents of the Nth record in the array to the procedure DoSomeWork(). DoSomeWork does not modify the contents of the record in any way. When I get back to main program after the call, all the record contents should be unchanged.
THE QUESTION: Now, DoSomeWork can take some time, so I then tried having it run on a separate thread. I call it like this:
When I invoke DoSomeWork on a new thread as above, the string contents of the xInfo() records get corrupted.
Yes the new thread for DoSomeWork allocates a number of new objects in memory, like NewMaps and map elements. But in my mind nothing being allocated should ever be able to overwrite contents of the original array or its strings as all of that was allocated ahead of time.
DoSomeWork reads from the xInfo record it is handed, but doesn't write to it. Yet the contents get corrupted, only when threading used. If I drop the CreateThread and call DoSomeWork directly, no problems.
Finally, DoSomeWork() uses a global map during processing. I wanted each worker thread to have its own copy of the map, so used 'threaded' declare. But discovered:
It seems clear that objects being allocated on the new thread by DoSomeWork (like SomeMap() above) are overwriting the string records that existed previously in the xInfo() records. But why?? Shouldn't PB know that the memory for both the xInfo array and its asociated strings are already in use?
(Thanks in advance to anyone who read this far!)
On program startup I create an array of structures. I wanted it global, but don't know at startup how many records I'll need so did it like this:
Code: Select all
Structure tFoo
String1.s
String2.s
EndStructure
Global Dim xInfo.tFoo(0) ; intially just one element
; ...
Redim xInfo(lMax) ; later in program, redim to the # of items I need and assign contents
; ...
xInfo(x)\String1="hello"
xInfo(x)\String2="world"
Later in the program I do some work, during which some new maps are created and used, etc. I want to pass it a single record from the array, so I've been doing it like this:
Code: Select all
DoSomeWork(@xInfo(n)) ; which I assume passes the address of the Nth record in array
; ...and in the procedure I have the parameter passing declared as:
Procedure DoSomeWork(*OneRecord.tFoo)
...
EndProcedure
THE QUESTION: Now, DoSomeWork can take some time, so I then tried having it run on a separate thread. I call it like this:
Code: Select all
lThreadHandle=CreateThread(@BackgroundWork(),n)
Procedure Backgroundwork(*Value)
Define n.l ;at this point should already be executing on new thread
n=*Value
DoSomeWork(@xInfo(n))
EndProcedure
Yes the new thread for DoSomeWork allocates a number of new objects in memory, like NewMaps and map elements. But in my mind nothing being allocated should ever be able to overwrite contents of the original array or its strings as all of that was allocated ahead of time.
DoSomeWork reads from the xInfo record it is handed, but doesn't write to it. Yet the contents get corrupted, only when threading used. If I drop the CreateThread and call DoSomeWork directly, no problems.
Finally, DoSomeWork() uses a global map during processing. I wanted each worker thread to have its own copy of the map, so used 'threaded' declare. But discovered:
Code: Select all
Threaded NewMap SomeMap() ; when declared like this, the xInfo corruption DOES occur.
Global NewMap SomeMap() ; when declared like this, corruption DOES NOT occur.
(Thanks in advance to anyone who read this far!)