Announcement

Collapse
No announcement yet.

LOCAL String Memory

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • LOCAL String Memory

    This is probably a dumb question, but it's been a long night. This is extracted from the PB help file:

    "When a dynamic string content is changed, the address of the string data will also change, but the string handle will remain in the same location. Therefore, it is important that your code refresh any pointers that target the string data memory locations directly."

    My question is, does the memory location of a variable-length string ONLY change if the string length changes?



  • #2
    Jerry, it has to do with how PB handles changes to strings, it copies changed data to a new string and if you had a pointer to the old string, it becomes invalid when a new string is created from a modified old string. Just get a current pointer to the new string and it will work fine.
    hutch at movsd dot com
    The MASM Forum

    www.masm32.com

    Comment


    • #3
      A test reveals that when using MID$ to replace characters, the location didn't change. (Obviously using POKE$ with a pointer doesn't change it either)
      Pretty much any other operation requires rebuilding the string so it's location changes (including REPLACE where newsubstring is the same length as oldsubstring)

      Comment


      • #4
        If the compiler is sure the length hasn't changed it will reuse the location with several statements like the SET statements and MID$.
        If concatenation and many other statements are used without those statements it will not reuse the location.
        Code:
        FUNCTION PBMAIN () AS LONG
         LOCAL s,sResult AS STRING, x AS LONG
         FOR x = 1 TO 5
          s="mike"
          GOSUB doit 'reuse
         NEXT
         MID$(s,1)="x"     :GOSUB doit 'reuse
         LSET s = "12345"  :GOSUB doit 'reuse
         RSET s = "9"      :GOSUB doit 'reuse
         CSET s = "X"      :GOSUB doit 'reuse
         LSET s = SPACE$(9):GOSUB doit 'reuse
         s = "AAAA"        :GOSUB doit 'reuse
         ? sResult
        EXIT FUNCTION
        doit:
         sResult+= USING$("& #",s,STRPTR(s)) + $CRLF
        RETURN
        END FUNCTION
        How long is an idea? Write it down.

        Comment


        • #5
          my question is, does the memory location of a variable-length string ONLY change if the string length changes?
          The location of the 32-bit integer which represents the string does not change. The location of the string data "may" change. String operations such as creation or changing using the PB statements or functions are proprietary. I'd suggest you assume nothing beyond the fact the memory location of the integer does not change.

          And BTW the thread title about "LOCAL" strings? If you have declared a PB variable as a "LOCAL STRING" it means the integer is stored on the stack. The integers representing GLOBAL and STATIC string variables are stored in the far heap. String data are always stored in the far heap.

          But let's go back a step... what are you doing that this is a concern? Maybe there is another way to handle whatever you are doing.
          Michael Mattias
          Tal Systems Inc. (retired)
          Racine WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            "far heap"? You're showing your age

            Far/near went away when we went to 32 bit.

            https://docs.microsoft.com/en-us/win...ocal-functions
            "Windows memory management does not provide a separate local heap and global heap, as 16-bit Windows does. As a result, the global and local families of functions are equivalent and choosing between them is a matter of personal preference. Note that the change from a 16-bit segmented memory model to a 32-bit virtual memory model has made some of the related global and local functions and their options unnecessary or meaningless. For example, there are no longer near and far pointers, because both local and global allocations return 32-bit virtual addresses."

            Comment


            • #7
              In 32 bit FLAT memory model, you shift from segments ALA near and far pointers to sections in a portable executable file and all data and code is addresses as NEAR in the 4 gig address space. Its a much cleaner and clearer system that the old segment/offset architecture. PB string memory is OLE memory and once you have the start address you can use it like any other allocated memory, its when you change the content IE: A string operation, it then gets written to another OLE string which will be at a different address.

              If you are only using the basic string name "mystring$" then it will work like normal, its when you already had a string address "StrPtr(xx$)" that you must get the pointer again because the old address is no longer valid.
              hutch at movsd dot com
              The MASM Forum

              www.masm32.com

              Comment


              • #8
                You are correct about one heap in 32-bit windows.. If I had to pick a word for it I guess we'd have to pick "Local" heap since it is subject to the 2 Gb limitation on user process memory regardless how much physical RAM is available. But from now on we'll try to just say "heap" or "system memory" without any distance prejudice.

                But the bolding the reference to the "difference" between near and far pointers? This refers to datatypes in the C language, not to the PB language or to Windows itself. It's more like the way you use an address back in the days of the DEF SEG statement. (20 bit addresses ==> paragraph + [short] offset).

                Then again, I guess I could just acknowledge I am showing my age. Hell, that does get me a senior citizen discount most everywhere.
                Michael Mattias
                Tal Systems Inc. (retired)
                Racine WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  Originally posted by Michael Mattias View Post
                  But let's go back a step... what are you doing that this is a concern? Maybe there is another way to handle whatever you are doing.
                  It's not so much a concern as an interest. For networking apps, I often set up fixed-length buffers large enough to handle any message size (usually up to around 100K) in order to avoid frequent allocation/de-allocation of memory. In most cases I use GlobalAlloc (or similar) or a STATIC fixed-length string so that I don't need to worry about stack space. But, I ran into an interesting behavior (which means that I just don't understand it) when launching multiple threads that all used a STATIC variable-length string (testing code below). It seems that all of the threads may be using the same memory space to store the string - I assume in global memory space. This is what I don't understand. So I'm hoping that someone can educate me on this, because I've probably been staring at it for too long.

                  Code:
                  #COMPILE EXE
                  #DIM ALL
                  
                  FUNCTION zCrc32 ALIAS "zCRC32" ( _
                    BYVAL pData AS DWORD, _   ' Pointer to string data to evaluate
                    BYVAL dSize AS LONG, _    ' Length of data string
                    BYVAL seed  AS DWORD _    ' Optional 32-bit seed value (0 for no seed)
                    ) AS DWORD                ' 32-bit CRC value
                  
                    #REGISTER NONE
                  
                    ! MOV EBX, seed
                    ! XOR EBX, &HFFFFFFFF
                    ! MOV ESI, dSize
                    ! CMP ESI, 0
                    ! JZ  QuitLoop
                    ! MOV EDI, pData
                    ! XOR EAX, EAX
                  NextByte:
                    ! MOV AL, BL
                    ! XOR AL, [EDI]
                    ! MOV ECX, Crc32Table[4*EAX]
                    ! SHR EBX, 8
                    ! XOR EBX, ECX
                    ! INC EDI
                    ! DEC ESI
                    ! JNZ NextByte
                  QuitLoop:
                    ! XOR EBX, &HFFFFFFFF
                    ! MOV FUNCTION, EBX
                    EXIT FUNCTION
                  
                  Crc32Table:
                    ! dd &H000000000&, &H077073096&, &H0EE0E612C&, &H0990951BA&
                    ! dd &H0076DC419&, &H0706AF48F&, &H0E963A535&, &H09E6495A3&
                    ! dd &H00EDB8832&, &H079DCB8A4&, &H0E0D5E91E&, &H097D2D988&
                    ! dd &H009B64C2B&, &H07EB17CBD&, &H0E7B82D07&, &H090BF1D91&
                    ! dd &H01DB71064&, &H06AB020F2&, &H0F3B97148&, &H084BE41DE&
                    ! dd &H01ADAD47D&, &H06DDDE4EB&, &H0F4D4B551&, &H083D385C7&
                    ! dd &H0136C9856&, &H0646BA8C0&, &H0FD62F97A&, &H08A65C9EC&
                    ! dd &H014015C4F&, &H063066CD9&, &H0FA0F3D63&, &H08D080DF5&
                    ! dd &H03B6E20C8&, &H04C69105E&, &H0D56041E4&, &H0A2677172&
                    ! dd &H03C03E4D1&, &H04B04D447&, &H0D20D85FD&, &H0A50AB56B&
                    ! dd &H035B5A8FA&, &H042B2986C&, &H0DBBBC9D6&, &H0ACBCF940&
                    ! dd &H032D86CE3&, &H045DF5C75&, &H0DCD60DCF&, &H0ABD13D59&
                    ! dd &H026D930AC&, &H051DE003A&, &H0C8D75180&, &H0BFD06116&
                    ! dd &H021B4F4B5&, &H056B3C423&, &H0CFBA9599&, &H0B8BDA50F&
                    ! dd &H02802B89E&, &H05F058808&, &H0C60CD9B2&, &H0B10BE924&
                    ! dd &H02F6F7C87&, &H058684C11&, &H0C1611DAB&, &H0B6662D3D&
                    ! dd &H076DC4190&, &H001DB7106&, &H098D220BC&, &H0EFD5102A&
                    ! dd &H071B18589&, &H006B6B51F&, &H09FBFE4A5&, &H0E8B8D433&
                    ! dd &H07807C9A2&, &H00F00F934&, &H09609A88E&, &H0E10E9818&
                    ! dd &H07F6A0DBB&, &H0086D3D2D&, &H091646C97&, &H0E6635C01&
                    ! dd &H06B6B51F4&, &H01C6C6162&, &H0856530D8&, &H0F262004E&
                    ! dd &H06C0695ED&, &H01B01A57B&, &H08208F4C1&, &H0F50FC457&
                    ! dd &H065B0D9C6&, &H012B7E950&, &H08BBEB8EA&, &H0FCB9887C&
                    ! dd &H062DD1DDF&, &H015DA2D49&, &H08CD37CF3&, &H0FBD44C65&
                    ! dd &H04DB26158&, &H03AB551CE&, &H0A3BC0074&, &H0D4BB30E2&
                    ! dd &H04ADFA541&, &H03DD895D7&, &H0A4D1C46D&, &H0D3D6F4FB&
                    ! dd &H04369E96A&, &H0346ED9FC&, &H0AD678846&, &H0DA60B8D0&
                    ! dd &H044042D73&, &H033031DE5&, &H0AA0A4C5F&, &H0DD0D7CC9&
                    ! dd &H05005713C&, &H0270241AA&, &H0BE0B1010&, &H0C90C2086&
                    ! dd &H05768B525&, &H0206F85B3&, &H0B966D409&, &H0CE61E49F&
                    ! dd &H05EDEF90E&, &H029D9C998&, &H0B0D09822&, &H0C7D7A8B4&
                    ! dd &H059B33D17&, &H02EB40D81&, &H0B7BD5C3B&, &H0C0BA6CAD&
                    ! dd &H0EDB88320&, &H09ABFB3B6&, &H003B6E20C&, &H074B1D29A&
                    ! dd &H0EAD54739&, &H09DD277AF&, &H004DB2615&, &H073DC1683&
                    ! dd &H0E3630B12&, &H094643B84&, &H00D6D6A3E&, &H07A6A5AA8&
                    ! dd &H0E40ECF0B&, &H09309FF9D&, &H00A00AE27&, &H07D079EB1&
                    ! dd &H0F00F9344&, &H08708A3D2&, &H01E01F268&, &H06906C2FE&
                    ! dd &H0F762575D&, &H0806567CB&, &H0196C3671&, &H06E6B06E7&
                    ! dd &H0FED41B76&, &H089D32BE0&, &H010DA7A5A&, &H067DD4ACC&
                    ! dd &H0F9B9DF6F&, &H08EBEEFF9&, &H017B7BE43&, &H060B08ED5&
                    ! dd &H0D6D6A3E8&, &H0A1D1937E&, &H038D8C2C4&, &H04FDFF252&
                    ! dd &H0D1BB67F1&, &H0A6BC5767&, &H03FB506DD&, &H048B2364B&
                    ! dd &H0D80D2BDA&, &H0AF0A1B4C&, &H036034AF6&, &H041047A60&
                    ! dd &H0DF60EFC3&, &H0A867DF55&, &H0316E8EEF&, &H04669BE79&
                    ! dd &H0CB61B38C&, &H0BC66831A&, &H0256FD2A0&, &H05268E236&
                    ! dd &H0CC0C7795&, &H0BB0B4703&, &H0220216B9&, &H05505262F&
                    ! dd &H0C5BA3BBE&, &H0B2BD0B28&, &H02BB45A92&, &H05CB36A04&
                    ! dd &H0C2D7FFA7&, &H0B5D0CF31&, &H02CD99E8B&, &H05BDEAE1D&
                    ! dd &H09B64C2B0&, &H0EC63F226&, &H0756AA39C&, &H0026D930A&
                    ! dd &H09C0906A9&, &H0EB0E363F&, &H072076785&, &H005005713&
                    ! dd &H095BF4A82&, &H0E2B87A14&, &H07BB12BAE&, &H00CB61B38&
                    ! dd &H092D28E9B&, &H0E5D5BE0D&, &H07CDCEFB7&, &H00BDBDF21&
                    ! dd &H086D3D2D4&, &H0F1D4E242&, &H068DDB3F8&, &H01FDA836E&
                    ! dd &H081BE16CD&, &H0F6B9265B&, &H06FB077E1&, &H018B74777&
                    ! dd &H088085AE6&, &H0FF0F6A70&, &H066063BCA&, &H011010B5C&
                    ! dd &H08F659EFF&, &H0F862AE69&, &H0616BFFD3&, &H0166CCF45&
                    ! dd &H0A00AE278&, &H0D70DD2EE&, &H04E048354&, &H03903B3C2&
                    ! dd &H0A7672661&, &H0D06016F7&, &H04969474D&, &H03E6E77DB&
                    ! dd &H0AED16A4A&, &H0D9D65ADC&, &H040DF0B66&, &H037D83BF0&
                    ! dd &H0A9BCAE53&, &H0DEBB9EC5&, &H047B2CF7F&, &H030B5FFE9&
                    ! dd &H0BDBDF21C&, &H0CABAC28A&, &H053B39330&, &H024B4A3A6&
                    ! dd &H0BAD03605&, &H0CDD70693&, &H054DE5729&, &H023D967BF&
                    ! dd &H0B3667A2E&, &H0C4614AB8&, &H05D681B02&, &H02A6F2B94&
                    ! dd &H0B40BBE37&, &H0C30C8EA1&, &H05A05DF1B&, &H02D02EF8D&
                  END FUNCTION  ' zCRC32
                  
                  MACRO sBase   = sData
                  MACRO sThread = sDataT
                  
                  SUB tPrint(BYVAL tNum AS LONG, BYREF sMsg AS STRING, BYVAL dVal AS DWORD) THREADSAFE
                    PRINT FORMAT$(tNum) & ": " & sMsg & STR$(dVal)
                  END SUB
                  
                  
                  THREAD FUNCTION MyThread (BYVAL tNum AS LONG) AS LONG
                    STATIC sThread AS STRING
                  '  local sThread as string
                  '  THREADED sThread AS STRING
                    LOCAL n AS LONG
                  
                    tPrint tNum, "Started with TID =", THREADID
                  
                    FOR n = 1 TO 10
                      sThread += "12345678901234567890123456789012345678901234567890"
                      sThread += "12345678901234567890123456789012345678901234567890"
                    NEXT n
                    SLEEP 1000
                    tPrint tNum, "Mem Ptr =", STRPTR(sThread)
                    tPrint tNum, "Length =", LEN(sThread)
                    tPrint tNum, "CRC =", zCrc32(STRPTR(sThread), LEN(sThread), 0)
                    tPrint tNum, "Stopping", 0
                  END FUNCTION  ' MyThread
                  
                  
                  FUNCTION PBMAIN () AS LONG
                    STATIC sData AS STRING
                    LOCAL n AS LONG
                    LOCAL ret AS LONG
                  
                  '  tPrint 0, "Started with TID =", THREADID
                  
                    '-- Baseline data?
                    FOR n = 1 TO 10
                      sBase += "12345678901234567890123456789012345678901234567890"
                      sBase += "12345678901234567890123456789012345678901234567890"
                    NEXT n
                    tPrint 0, "Mem Ptr =", STRPTR(sBase)
                    tPrint 0, "Length =", LEN(sBase)
                    tPrint 0, "CRC =", zCrc32(STRPTR(sBase), LEN(sBase), 0)
                    SLEEP 100
                    FOR n = 1 TO 4
                      THREAD CREATE MyThread(n) TO ret
                      THREAD CLOSE ret TO ret
                      SLEEP 10
                    NEXT n
                  
                  Exitmain:
                    WAITKEY$
                  
                  END FUNCTION

                  Comment


                  • #10
                    Static anf global variables aren't thread safe, only local variables are. With PB you can also use threaded variables.
                    Forum: http://www.jose.it-berater.org/smfforum/index.php

                    Comment


                    • #11
                      Like you wondered.... you ARE using the same memory in all thread contexts if your PB Variable is defined as STATIC.

                      If THREADED variables are not available in your version of the compiler, you might be interested in..

                      Terminate Worker Threads Using Windows Events (and Using Thread Local Storage) Demo Dec 23 2005

                      Thread local storage is what PB 'THREADED' variables are based on.. and what you used for "per thread persistent data" before THREADED variables were introduced. (Post #3 that thread is the TLS part)
                      Michael Mattias
                      Tal Systems Inc. (retired)
                      Racine WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        I'm trying not to overthink this, and the moral of the story for me is be very careful with STATIC vars in a multi-threaded environment - which is where most of my apps live.

                        From an academic perspective, I'm comfortable with LOCAL and THREADED vars (and GlobalAlloc memory) but the behavior of memory shared by STATIC vars still confuses me. Specifically, it seems that STATIC vars used by threads with the same name are shared but STATIC vars used with threads with a different name (same name for vars) are not shared between the two groups of threads. I modified the earlier code to launch two groups of identical threads (other than a reporting line).

                        This behavior is probably really obvious to you, so please excuse my ignorance.

                        Code:
                        #COMPILE EXE
                        #DIM ALL
                        
                        FUNCTION zCrc32 ALIAS "zCRC32" ( _
                          BYVAL pData AS DWORD, _   ' Pointer to string data to evaluate
                          BYVAL dSize AS LONG, _    ' Length of data string
                          BYVAL seed  AS DWORD _    ' Optional 32-bit seed value (0 for no seed)
                          ) AS DWORD                ' 32-bit CRC value
                        
                          #REGISTER NONE
                        
                          ! MOV EBX, seed
                          ! XOR EBX, &HFFFFFFFF
                          ! MOV ESI, dSize
                          ! CMP ESI, 0
                          ! JZ  QuitLoop
                          ! MOV EDI, pData
                          ! XOR EAX, EAX
                        NextByte:
                          ! MOV AL, BL
                          ! XOR AL, [EDI]
                          ! MOV ECX, Crc32Table[4*EAX]
                          ! SHR EBX, 8
                          ! XOR EBX, ECX
                          ! INC EDI
                          ! DEC ESI
                          ! JNZ NextByte
                        QuitLoop:
                          ! XOR EBX, &HFFFFFFFF
                          ! MOV FUNCTION, EBX
                          EXIT FUNCTION
                        
                        Crc32Table:
                          ! dd &H000000000&, &H077073096&, &H0EE0E612C&, &H0990951BA&
                          ! dd &H0076DC419&, &H0706AF48F&, &H0E963A535&, &H09E6495A3&
                          ! dd &H00EDB8832&, &H079DCB8A4&, &H0E0D5E91E&, &H097D2D988&
                          ! dd &H009B64C2B&, &H07EB17CBD&, &H0E7B82D07&, &H090BF1D91&
                          ! dd &H01DB71064&, &H06AB020F2&, &H0F3B97148&, &H084BE41DE&
                          ! dd &H01ADAD47D&, &H06DDDE4EB&, &H0F4D4B551&, &H083D385C7&
                          ! dd &H0136C9856&, &H0646BA8C0&, &H0FD62F97A&, &H08A65C9EC&
                          ! dd &H014015C4F&, &H063066CD9&, &H0FA0F3D63&, &H08D080DF5&
                          ! dd &H03B6E20C8&, &H04C69105E&, &H0D56041E4&, &H0A2677172&
                          ! dd &H03C03E4D1&, &H04B04D447&, &H0D20D85FD&, &H0A50AB56B&
                          ! dd &H035B5A8FA&, &H042B2986C&, &H0DBBBC9D6&, &H0ACBCF940&
                          ! dd &H032D86CE3&, &H045DF5C75&, &H0DCD60DCF&, &H0ABD13D59&
                          ! dd &H026D930AC&, &H051DE003A&, &H0C8D75180&, &H0BFD06116&
                          ! dd &H021B4F4B5&, &H056B3C423&, &H0CFBA9599&, &H0B8BDA50F&
                          ! dd &H02802B89E&, &H05F058808&, &H0C60CD9B2&, &H0B10BE924&
                          ! dd &H02F6F7C87&, &H058684C11&, &H0C1611DAB&, &H0B6662D3D&
                          ! dd &H076DC4190&, &H001DB7106&, &H098D220BC&, &H0EFD5102A&
                          ! dd &H071B18589&, &H006B6B51F&, &H09FBFE4A5&, &H0E8B8D433&
                          ! dd &H07807C9A2&, &H00F00F934&, &H09609A88E&, &H0E10E9818&
                          ! dd &H07F6A0DBB&, &H0086D3D2D&, &H091646C97&, &H0E6635C01&
                          ! dd &H06B6B51F4&, &H01C6C6162&, &H0856530D8&, &H0F262004E&
                          ! dd &H06C0695ED&, &H01B01A57B&, &H08208F4C1&, &H0F50FC457&
                          ! dd &H065B0D9C6&, &H012B7E950&, &H08BBEB8EA&, &H0FCB9887C&
                          ! dd &H062DD1DDF&, &H015DA2D49&, &H08CD37CF3&, &H0FBD44C65&
                          ! dd &H04DB26158&, &H03AB551CE&, &H0A3BC0074&, &H0D4BB30E2&
                          ! dd &H04ADFA541&, &H03DD895D7&, &H0A4D1C46D&, &H0D3D6F4FB&
                          ! dd &H04369E96A&, &H0346ED9FC&, &H0AD678846&, &H0DA60B8D0&
                          ! dd &H044042D73&, &H033031DE5&, &H0AA0A4C5F&, &H0DD0D7CC9&
                          ! dd &H05005713C&, &H0270241AA&, &H0BE0B1010&, &H0C90C2086&
                          ! dd &H05768B525&, &H0206F85B3&, &H0B966D409&, &H0CE61E49F&
                          ! dd &H05EDEF90E&, &H029D9C998&, &H0B0D09822&, &H0C7D7A8B4&
                          ! dd &H059B33D17&, &H02EB40D81&, &H0B7BD5C3B&, &H0C0BA6CAD&
                          ! dd &H0EDB88320&, &H09ABFB3B6&, &H003B6E20C&, &H074B1D29A&
                          ! dd &H0EAD54739&, &H09DD277AF&, &H004DB2615&, &H073DC1683&
                          ! dd &H0E3630B12&, &H094643B84&, &H00D6D6A3E&, &H07A6A5AA8&
                          ! dd &H0E40ECF0B&, &H09309FF9D&, &H00A00AE27&, &H07D079EB1&
                          ! dd &H0F00F9344&, &H08708A3D2&, &H01E01F268&, &H06906C2FE&
                          ! dd &H0F762575D&, &H0806567CB&, &H0196C3671&, &H06E6B06E7&
                          ! dd &H0FED41B76&, &H089D32BE0&, &H010DA7A5A&, &H067DD4ACC&
                          ! dd &H0F9B9DF6F&, &H08EBEEFF9&, &H017B7BE43&, &H060B08ED5&
                          ! dd &H0D6D6A3E8&, &H0A1D1937E&, &H038D8C2C4&, &H04FDFF252&
                          ! dd &H0D1BB67F1&, &H0A6BC5767&, &H03FB506DD&, &H048B2364B&
                          ! dd &H0D80D2BDA&, &H0AF0A1B4C&, &H036034AF6&, &H041047A60&
                          ! dd &H0DF60EFC3&, &H0A867DF55&, &H0316E8EEF&, &H04669BE79&
                          ! dd &H0CB61B38C&, &H0BC66831A&, &H0256FD2A0&, &H05268E236&
                          ! dd &H0CC0C7795&, &H0BB0B4703&, &H0220216B9&, &H05505262F&
                          ! dd &H0C5BA3BBE&, &H0B2BD0B28&, &H02BB45A92&, &H05CB36A04&
                          ! dd &H0C2D7FFA7&, &H0B5D0CF31&, &H02CD99E8B&, &H05BDEAE1D&
                          ! dd &H09B64C2B0&, &H0EC63F226&, &H0756AA39C&, &H0026D930A&
                          ! dd &H09C0906A9&, &H0EB0E363F&, &H072076785&, &H005005713&
                          ! dd &H095BF4A82&, &H0E2B87A14&, &H07BB12BAE&, &H00CB61B38&
                          ! dd &H092D28E9B&, &H0E5D5BE0D&, &H07CDCEFB7&, &H00BDBDF21&
                          ! dd &H086D3D2D4&, &H0F1D4E242&, &H068DDB3F8&, &H01FDA836E&
                          ! dd &H081BE16CD&, &H0F6B9265B&, &H06FB077E1&, &H018B74777&
                          ! dd &H088085AE6&, &H0FF0F6A70&, &H066063BCA&, &H011010B5C&
                          ! dd &H08F659EFF&, &H0F862AE69&, &H0616BFFD3&, &H0166CCF45&
                          ! dd &H0A00AE278&, &H0D70DD2EE&, &H04E048354&, &H03903B3C2&
                          ! dd &H0A7672661&, &H0D06016F7&, &H04969474D&, &H03E6E77DB&
                          ! dd &H0AED16A4A&, &H0D9D65ADC&, &H040DF0B66&, &H037D83BF0&
                          ! dd &H0A9BCAE53&, &H0DEBB9EC5&, &H047B2CF7F&, &H030B5FFE9&
                          ! dd &H0BDBDF21C&, &H0CABAC28A&, &H053B39330&, &H024B4A3A6&
                          ! dd &H0BAD03605&, &H0CDD70693&, &H054DE5729&, &H023D967BF&
                          ! dd &H0B3667A2E&, &H0C4614AB8&, &H05D681B02&, &H02A6F2B94&
                          ! dd &H0B40BBE37&, &H0C30C8EA1&, &H05A05DF1B&, &H02D02EF8D&
                        END FUNCTION  ' zCRC32
                        
                        MACRO sBase   = sData
                        MACRO sThread = sData
                        
                        SUB tPrint(BYVAL tNum AS LONG, BYREF sMsg AS STRING, BYVAL dVal AS DWORD) THREADSAFE
                          PRINT FORMAT$(tNum) & ": " & sMsg & STR$(dVal)
                        END SUB
                        
                        
                        THREAD FUNCTION MyThread (BYVAL tNum AS LONG) AS LONG
                          STATIC sThread AS STRING
                        '  local sThread as string
                        '  THREADED sThread AS STRING
                          LOCAL n AS LONG
                        
                          '++++++++++ Added +++++++++++
                          STATIC z AS LONG
                          INCR z
                          '++++++++++++++++++++++++++++
                        
                          tPrint tNum, "Started with TID =", THREADID
                        
                          FOR n = 1 TO 10
                            sThread += "12345678901234567890123456789012345678901234567890"
                            sThread += "12345678901234567890123456789012345678901234567890"
                          NEXT n
                          SLEEP 1000
                          tPrint tNum, "Mem Ptr =", STRPTR(sThread)
                          tPrint tNum, "Length =", LEN(sThread)
                          tPrint tNum, "CRC =", zCrc32(STRPTR(sThread), LEN(sThread), 0)
                          '++++++++++++ Added +++++++++++
                          tPrint tNum, "z=", z
                          '++++++++++++++++++++++++++++++
                          tPrint tNum, "Stopping", 0
                        
                        END FUNCTION  ' MyThread
                        
                        
                        THREAD FUNCTION MyThread2 (BYVAL tNum AS LONG) AS LONG
                          STATIC sThread AS STRING
                        '  local sThread as string
                        '  THREADED sThread AS STRING
                          LOCAL n AS LONG
                        
                          '++++++++++ Added +++++++++++
                          STATIC z AS LONG
                           tNum += 10
                          INCR z
                          '++++++++++++++++++++++++++++
                        
                          tPrint tNum, "Started with TID =", THREADID
                        
                          FOR n = 1 TO 10
                            sThread += "12345678901234567890123456789012345678901234567890"
                            sThread += "12345678901234567890123456789012345678901234567890"
                          NEXT n
                          SLEEP 1000
                          tPrint tNum, "Mem Ptr =", STRPTR(sThread)
                          tPrint tNum, "Length =", LEN(sThread)
                          tPrint tNum, "CRC =", zCrc32(STRPTR(sThread), LEN(sThread), 0)
                          '++++++++++++ Added +++++++++++
                          tPrint tNum, "z=", z
                          '++++++++++++++++++++++++++++++
                          tPrint tNum, "Stopping", 0
                        
                        END FUNCTION  ' MyThread
                        
                        
                        FUNCTION PBMAIN () AS LONG
                          STATIC sData AS STRING
                          LOCAL n AS LONG
                          LOCAL ret AS LONG
                        
                        '  tPrint 0, "Started with TID =", THREADID
                        
                          '-- Baseline data?
                          FOR n = 1 TO 10
                            sBase += "12345678901234567890123456789012345678901234567890"
                            sBase += "12345678901234567890123456789012345678901234567890"
                          NEXT n
                          tPrint 0, "Mem Ptr =", STRPTR(sBase)
                          tPrint 0, "Length =", LEN(sBase)
                          tPrint 0, "CRC =", zCrc32(STRPTR(sBase), LEN(sBase), 0)
                          SLEEP 100
                          FOR n = 1 TO 2
                            THREAD CREATE MyThread(n) TO ret
                            THREAD CLOSE ret TO ret
                            '+++++++++++++++ Added +++++++++++++++++
                            THREAD CREATE MyThread2(n) TO ret
                            THREAD CLOSE ret TO ret
                            '+++++++++++++++++++++++++++++++++++++++
                            SLEEP 100
                          NEXT n
                        
                        Exitmain:
                          WAITKEY$
                        
                        END FUNCTION

                        Comment


                        • #13
                          1 Pass string value to a thread using a string pointer.
                          2 Thread calls a threadsafe helper function.
                          3 Helper function places results in gsResult().
                          Code:
                          #DIM ALL
                          GLOBAL gsResult() AS STRING
                          
                          FUNCTION PBMAIN () AS LONG
                           LOCAL n,ret AS LONG, s AS STRING
                           FOR n = 1 TO 4
                            s = USING$("String #",n)
                            THREAD CREATE MyThread(STRPTR(s)) TO ret
                            THREAD CLOSE ret TO ret
                            SLEEP 10 'required
                           NEXT n
                           DO:SLEEP 50:LOOP UNTIL THREADCOUNT = 1
                           ? JOIN$(gsResult(),$CR),,"gsResult()"
                          END FUNCTION
                          
                          THREAD FUNCTION MyThread (BYVAL pData AS ASCIIZ PTR) AS LONG
                           MyThreadHelper(pData)
                          END FUNCTION
                          
                          SUB MyThreadHelper(BYVAL pData AS ASCIIZ PTR) THREADSAFE
                           LOCAL s AS STRING, upper,crc AS DWORD
                           s = @pData
                           crc = zCrc32(pData, LEN(s), 0)
                           upper = UBOUND(gsResult)+1
                           REDIM PRESERVE gsResult(upper)
                           gsResult(upper)=USING$("& crc=#",s,crc)
                          END SUB
                          
                          FUNCTION zCrc32 ALIAS "zCRC32" ( _
                            BYVAL pData AS DWORD, _   ' Pointer to string data to evaluate
                            BYVAL dSize AS LONG, _    ' Length of data string
                            BYVAL seed  AS DWORD _    ' Optional 32-bit seed value (0 for no seed)
                            ) AS DWORD     ' 32-bit CRC value
                          
                            #REGISTER NONE
                          
                            ! MOV EBX, seed
                            ! XOR EBX, &HFFFFFFFF
                            ! MOV ESI, dSize
                            ! CMP ESI, 0
                            ! JZ  QuitLoop
                            ! MOV EDI, pData
                            ! XOR EAX, EAX
                          NextByte:
                            ! MOV AL, BL
                            ! XOR AL, [EDI]
                            ! MOV ECX, Crc32Table[4*EAX]
                            ! SHR EBX, 8
                            ! XOR EBX, ECX
                            ! INC EDI
                            ! DEC ESI
                            ! JNZ NextByte
                          QuitLoop:
                            ! XOR EBX, &HFFFFFFFF
                            ! MOV FUNCTION, EBX
                            EXIT FUNCTION
                          
                          Crc32Table:
                            ! dd &H000000000&, &H077073096&, &H0EE0E612C&, &H0990951BA&
                            ! dd &H0076DC419&, &H0706AF48F&, &H0E963A535&, &H09E6495A3&
                            ! dd &H00EDB8832&, &H079DCB8A4&, &H0E0D5E91E&, &H097D2D988&
                            ! dd &H009B64C2B&, &H07EB17CBD&, &H0E7B82D07&, &H090BF1D91&
                            ! dd &H01DB71064&, &H06AB020F2&, &H0F3B97148&, &H084BE41DE&
                            ! dd &H01ADAD47D&, &H06DDDE4EB&, &H0F4D4B551&, &H083D385C7&
                            ! dd &H0136C9856&, &H0646BA8C0&, &H0FD62F97A&, &H08A65C9EC&
                            ! dd &H014015C4F&, &H063066CD9&, &H0FA0F3D63&, &H08D080DF5&
                            ! dd &H03B6E20C8&, &H04C69105E&, &H0D56041E4&, &H0A2677172&
                            ! dd &H03C03E4D1&, &H04B04D447&, &H0D20D85FD&, &H0A50AB56B&
                            ! dd &H035B5A8FA&, &H042B2986C&, &H0DBBBC9D6&, &H0ACBCF940&
                            ! dd &H032D86CE3&, &H045DF5C75&, &H0DCD60DCF&, &H0ABD13D59&
                            ! dd &H026D930AC&, &H051DE003A&, &H0C8D75180&, &H0BFD06116&
                            ! dd &H021B4F4B5&, &H056B3C423&, &H0CFBA9599&, &H0B8BDA50F&
                            ! dd &H02802B89E&, &H05F058808&, &H0C60CD9B2&, &H0B10BE924&
                            ! dd &H02F6F7C87&, &H058684C11&, &H0C1611DAB&, &H0B6662D3D&
                            ! dd &H076DC4190&, &H001DB7106&, &H098D220BC&, &H0EFD5102A&
                            ! dd &H071B18589&, &H006B6B51F&, &H09FBFE4A5&, &H0E8B8D433&
                            ! dd &H07807C9A2&, &H00F00F934&, &H09609A88E&, &H0E10E9818&
                            ! dd &H07F6A0DBB&, &H0086D3D2D&, &H091646C97&, &H0E6635C01&
                            ! dd &H06B6B51F4&, &H01C6C6162&, &H0856530D8&, &H0F262004E&
                            ! dd &H06C0695ED&, &H01B01A57B&, &H08208F4C1&, &H0F50FC457&
                            ! dd &H065B0D9C6&, &H012B7E950&, &H08BBEB8EA&, &H0FCB9887C&
                            ! dd &H062DD1DDF&, &H015DA2D49&, &H08CD37CF3&, &H0FBD44C65&
                            ! dd &H04DB26158&, &H03AB551CE&, &H0A3BC0074&, &H0D4BB30E2&
                            ! dd &H04ADFA541&, &H03DD895D7&, &H0A4D1C46D&, &H0D3D6F4FB&
                            ! dd &H04369E96A&, &H0346ED9FC&, &H0AD678846&, &H0DA60B8D0&
                            ! dd &H044042D73&, &H033031DE5&, &H0AA0A4C5F&, &H0DD0D7CC9&
                            ! dd &H05005713C&, &H0270241AA&, &H0BE0B1010&, &H0C90C2086&
                            ! dd &H05768B525&, &H0206F85B3&, &H0B966D409&, &H0CE61E49F&
                            ! dd &H05EDEF90E&, &H029D9C998&, &H0B0D09822&, &H0C7D7A8B4&
                            ! dd &H059B33D17&, &H02EB40D81&, &H0B7BD5C3B&, &H0C0BA6CAD&
                            ! dd &H0EDB88320&, &H09ABFB3B6&, &H003B6E20C&, &H074B1D29A&
                            ! dd &H0EAD54739&, &H09DD277AF&, &H004DB2615&, &H073DC1683&
                            ! dd &H0E3630B12&, &H094643B84&, &H00D6D6A3E&, &H07A6A5AA8&
                            ! dd &H0E40ECF0B&, &H09309FF9D&, &H00A00AE27&, &H07D079EB1&
                            ! dd &H0F00F9344&, &H08708A3D2&, &H01E01F268&, &H06906C2FE&
                            ! dd &H0F762575D&, &H0806567CB&, &H0196C3671&, &H06E6B06E7&
                            ! dd &H0FED41B76&, &H089D32BE0&, &H010DA7A5A&, &H067DD4ACC&
                            ! dd &H0F9B9DF6F&, &H08EBEEFF9&, &H017B7BE43&, &H060B08ED5&
                            ! dd &H0D6D6A3E8&, &H0A1D1937E&, &H038D8C2C4&, &H04FDFF252&
                            ! dd &H0D1BB67F1&, &H0A6BC5767&, &H03FB506DD&, &H048B2364B&
                            ! dd &H0D80D2BDA&, &H0AF0A1B4C&, &H036034AF6&, &H041047A60&
                            ! dd &H0DF60EFC3&, &H0A867DF55&, &H0316E8EEF&, &H04669BE79&
                            ! dd &H0CB61B38C&, &H0BC66831A&, &H0256FD2A0&, &H05268E236&
                            ! dd &H0CC0C7795&, &H0BB0B4703&, &H0220216B9&, &H05505262F&
                            ! dd &H0C5BA3BBE&, &H0B2BD0B28&, &H02BB45A92&, &H05CB36A04&
                            ! dd &H0C2D7FFA7&, &H0B5D0CF31&, &H02CD99E8B&, &H05BDEAE1D&
                            ! dd &H09B64C2B0&, &H0EC63F226&, &H0756AA39C&, &H0026D930A&
                            ! dd &H09C0906A9&, &H0EB0E363F&, &H072076785&, &H005005713&
                            ! dd &H095BF4A82&, &H0E2B87A14&, &H07BB12BAE&, &H00CB61B38&
                            ! dd &H092D28E9B&, &H0E5D5BE0D&, &H07CDCEFB7&, &H00BDBDF21&
                            ! dd &H086D3D2D4&, &H0F1D4E242&, &H068DDB3F8&, &H01FDA836E&
                            ! dd &H081BE16CD&, &H0F6B9265B&, &H06FB077E1&, &H018B74777&
                            ! dd &H088085AE6&, &H0FF0F6A70&, &H066063BCA&, &H011010B5C&
                            ! dd &H08F659EFF&, &H0F862AE69&, &H0616BFFD3&, &H0166CCF45&
                            ! dd &H0A00AE278&, &H0D70DD2EE&, &H04E048354&, &H03903B3C2&
                            ! dd &H0A7672661&, &H0D06016F7&, &H04969474D&, &H03E6E77DB&
                            ! dd &H0AED16A4A&, &H0D9D65ADC&, &H040DF0B66&, &H037D83BF0&
                            ! dd &H0A9BCAE53&, &H0DEBB9EC5&, &H047B2CF7F&, &H030B5FFE9&
                            ! dd &H0BDBDF21C&, &H0CABAC28A&, &H053B39330&, &H024B4A3A6&
                            ! dd &H0BAD03605&, &H0CDD70693&, &H054DE5729&, &H023D967BF&
                            ! dd &H0B3667A2E&, &H0C4614AB8&, &H05D681B02&, &H02A6F2B94&
                            ! dd &H0B40BBE37&, &H0C30C8EA1&, &H05A05DF1B&, &H02D02EF8D&
                          END FUNCTION  ' zCRC32
                          How long is an idea? Write it down.

                          Comment


                          • #14
                            You are correct. If multiple threads are created using the same function name the value of the static variable becomes unpredictable.
                            If separate names are used for each thread the other threads static values are separate.
                            If a function has a static variable and is used by multiple threads be sure it is protected.
                            How long is an idea? Write it down.

                            Comment


                            • #15
                              A STATIC variable's storage is the same as for a GLOBAL; but the variable's NAME is valid only within the procedure in which it is defined.
                              Michael Mattias
                              Tal Systems Inc. (retired)
                              Racine WI USA
                              [email protected]
                              http://www.talsystems.com

                              Comment


                              • #16
                                Originally posted by Jerry Wilson View Post
                                From an academic perspective, I'm comfortable with LOCAL and THREADED vars (and GlobalAlloc memory) but the behavior of memory shared by STATIC vars still confuses me. Specifically, it seems that STATIC vars used by threads with the same name are shared but STATIC vars used with threads with a different name (same name for vars) are not shared between the two groups of threads. I modified the earlier code to launch two groups of identical threads (other than a reporting line).

                                This behavior is probably really obvious to you, so please excuse my ignorance.
                                The key point is that STATIC variables are local to a function/procedure and retain their values as long as the pogram is running.

                                A thread is just one function/procedure which can run multiple times concurrently. A thread is not a different function every time it runs. It's the same if the thread function calls another function containing a STATIC vairable unless the second function is declared as THREADSAFE.
                                Last edited by Stuart McLachlan; 26 Jun 2020, 01:00 AM.

                                Comment


                                • #17
                                  Originally posted by Mike Doty View Post
                                  1 Pass string value to a thread using a string pointer.
                                  2 Thread calls a threadsafe helper function.
                                  3 Helper function places results in gsResult().
                                  Code:
                                  #DIM ALL
                                  GLOBAL gsResult() AS STRING
                                  
                                  FUNCTION PBMAIN () AS LONG
                                  LOCAL n,ret AS LONG, s AS STRING
                                  FOR n = 1 TO 4
                                  s = USING$("String #",n)
                                  THREAD CREATE MyThread(STRPTR(s)) TO ret
                                  THREAD CLOSE ret TO ret
                                  SLEEP 10 'required
                                  NEXT n
                                  DO:SLEEP 50:LOOP UNTIL THREADCOUNT = 1
                                  ? JOIN$(gsResult(),$CR),,"gsResult()"
                                  END FUNCTION
                                  
                                  THREAD FUNCTION MyThread (BYVAL pData AS ASCIIZ PTR) AS LONG
                                  MyThreadHelper(pData)
                                  END FUNCTION
                                  
                                  SUB MyThreadHelper(BYVAL pData AS ASCIIZ PTR) THREADSAFE
                                  That's rather pointless. If all your thread does is call a threadsafe function/procedure, every invocation of it will be held until every previous invocation terminates.
                                  It will be considerably slower than just calling MyThreadHelper directly multiple times from PBMain

                                  Comment


                                  • #18
                                    Multiple thread code works fine if the memory each thread uses is allocated in each thread, where you can get problems is in communication between threads through commonly accessed memory, primarily GLOBAL variables. If memory is allocated in a thread, it only has scope in that thread and is thus thread safe but with a GLOBAL variable/memory address, you have the problem of one thread writing to the global memory while another thread wants to do the same, basically a synchronisation problem.

                                    There are multiple techniques for scheduling memory access so that you don't get conflicts, critical sections etc .... Apart from communication between threads using memory that is available in a GLOBAL scope, you can emulate thread local globals by a simple mechanism of creating a structure with as many members as is required, place the thread local memory address within the structure and simply pass the structure address to any procedure that is called and you can access that memory from any location in the call tree in the individual thread.

                                    RE : The use of STATIC variables, Michael is correct here, a STATIC variable is a GLOBAL variable that has a LOCAL pointer attached to it. The only thread safe memory or variables are either LOCAL or locally allocated dynamic memory. With this you can write thread safe code as long as you put in place a method of synchronisation with GLOBAL memory so that you do not get memory overwrites.
                                    hutch at movsd dot com
                                    The MASM Forum

                                    www.masm32.com

                                    Comment


                                    • #19
                                      Originally posted by Stuart McLachlan View Post
                                      A thread is just one function/procedure which can run multiple times concurrently. A thread is not a different function every time it runs.
                                      Originally posted by Steve Hutchesson View Post
                                      RE : The use of STATIC variables, Michael is correct here, a STATIC variable is a GLOBAL variable that has a LOCAL pointer attached to it.
                                      I agree with Stuart and, in the context of threads/functions with the same name, with Steve and Michael (global data). Perhaps PB associates the STATIC data and it's associated memory location with the function name or reference code pointer (thinking about how CreateThread is called under the covers). If you start different threads referencing different "THREAD FUNCTION xxx" code, the "global" STATIC data is not shared. Any other function/procedure that has a unique name (pretty much all in an app) also do not appear to share STATIC memory with anyone else. Kind of a scope thing.

                                      I'm not sure if my hypothesis is completely correct but I do know how to protect data in a group of identical threads using LOCAL vars or allocating GLOBAL memory. I actually do launch multiple threads for a number of reasons, such as working with sockets.

                                      Thanks to all for your input.

                                      Comment


                                      • #20
                                        See post #15
                                        How long is an idea? Write it down.

                                        Comment

                                        Working...
                                        X