August 18, 2019, 04:24:33 pm

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Deletion of memory.

Started by John Syl., March 11, 2008, 11:05:05 am

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

John Syl.

March 11, 2008, 11:05:05 am Last Edit: March 11, 2008, 11:25:31 am by John Syl. (puddytat)
Hi guys after a long period of programming inactivity I decided to get back into it, the trauma has not been bad up to now then I hit this problem

My problem is that I create a structure and reserve memory for it as:

SStruct *sst;

sst=new(SStruct,1);

The content of the structure is irrelevant (I think), but now I need to pass this pointer to a thread
I have used PostMessageThread, and use the unsigned it wparam as a way of passing the pointer for the structure.


The thread can retrieve the pointer and accesses the data using

     *(SStruct)wparam.member.

This all works fine, my only problem is how (if possible) can I get the thread to free the structure memory when it's finished with it? 

I have tried using

     delete *(pointer)wparam

this passes the compiler but does not seem to free the memory.

If I use delete *(SStruct)wparam the compiler throws an error.

If the creator of the pointer sst uses  delete sst it can free the memory, but it has no idea if the data has been used and therefore freeing it at that point will cause a system error if the thread then tries to access it after it has been deleted
.
The obvious way is for the user to free it...but how?
Intel 3.6 p4 ht, XP home,2 gb mem, 400 gb hd 20gb raid 0, Nvidia 6600le.
AMD k6-2 500, 40gb.

Started on PDP11 Assembler, BASIC, GWBASIC, 6502, Z80, 80x86, Java, Pascal, C, C++, 
IBasic (std & pro), Aurora, EBasic.  (Master of none, but it's been fun!)

Mike Stefanik

March 11, 2008, 12:11:28 pm #1 Last Edit: March 11, 2008, 12:30:12 pm by Mike Stefanik
I may be missing something, but what you've described does not sound thread safe to me. Also, I'm curious, is there a particular reason that you're using PostThreadMessage to do this? It would seem that a global pointer would be more straight forward, and in either case you're going to need to make sure that you're synchronizing access to that data. Generally speaking, I recommend following the rule "the thread that creates the instance of an object (or structure) is responsible for destroying that instance". If you want to make sure that your worker thread has consumed the data and no longer needs it, then you use the Windows event mechanism for signalling (CreateEvent, WaitForSingleObject and friends).

Edit: Just as a general comment for anyone, if you want to write a multi-threaded application and do it correctly (safely), it can get a bit complex. You need to understand how Windows threading works, as well as data synchronization (critical sections, mutexes, interlock operations, etc.) and event signaling. Avoid "tricks" such as assuming that assigning a value to a DWORD occurs in a single cycle and therefore doesn't require synchronization (this is not thread safe on multi-core systems, and dual- and quad-core systems have become common out there). Also, when testing a multi-threaded application, it's best if you actually test it on a multi-core or multi-proc system; hyperthreading doesn't really count there.
Mike Stefanik
www.catalyst.com
Catalyst Development Corporation

John Syl.

Thanks Mike, it is indeed a complex problem and it is with thread safety in mind that I decided to try and use the PostThreadMessage..which works fine except for this problem, I have the option of returning a message to the sending thread that it is safe to delete the data, but I was hoping there is a simpler solution.

I thought about global pointers but there is the intention to have anything from 50 to 300 threads, the number of threads running varies over time.  Each thread runs independently and has no connection or interaction with any other thread except by the posting of messages.  The use of global pointers is actually more complex due to the dynamic creation  and destruction of threads.

Any one of the threads needs to communicate with any other thread depending on data posted from a central process.

The data being passed from one thread to another is only used by the receiving thread, the sender merely formats the data and once formatted and the message posted, it has no use in the data.



The possibility of data synchronisation does not arise as each thread is handling different data and shares nothing except by use of PostThreadMessage and then once it has sent the message it has no interest in the data.  As you point out the threads become unsafe in the event the sender destroys the data before the receiver has accessed it or during access by the receiver.

I suppose it is like a post office, a person sends a letter and once posted has no access to that letter once in the post, on receiving the letter, the recipient can then deal with the letter without any chance of interference from the sender.

However, it would seem strange for the recipient to return the letter to the originator for destruction.

regards John



Intel 3.6 p4 ht, XP home,2 gb mem, 400 gb hd 20gb raid 0, Nvidia 6600le.
AMD k6-2 500, 40gb.

Started on PDP11 Assembler, BASIC, GWBASIC, 6502, Z80, 80x86, Java, Pascal, C, C++, 
IBasic (std & pro), Aurora, EBasic.  (Master of none, but it's been fun!)

Mike Stefanik

Back to the original question, try actually using pointer variables there. For example:

Code Select

#autodefine "off"

struct Test
{
    string m_strValue;
    unsigned int m_nValue;
}

global sub main()
{
    Test *pTest1 = null;
    Test *pTest2 = null;
    unsigned int lParam = 0;
   
    // make sure that a console window is open
    OpenConsole();

    // create and populate the structure
    pTest1 = new(Test, 1);
    pTest1->m_strValue = "This is a test";
    pTest1->m_nValue = 12345;

    // pointer to unsigned int
    lParam = &*pTest1;

    // unsigned int back to a pointer
    pTest2 = *(Test)lParam;

    print("String Value=[" + pTest2->m_strValue + "] Integer Value=" + NumToStr(pTest2->m_nValue));

    // delete the structure
    delete pTest2;
    pTest1 = pTest2 = null;

    while GetKey() = "";
}


Coming from a C++ background, I've always thought the way Aurora handles pointers and casts is a bit strange; C-like, but not exactly. In any case, it's probably just that the compiler doesn't understand what do when you're handing a cast to the delete operator. So instead of:

Code Select

delete *(SStruct)wParam;


Try:

Code Select

SStruct *pTemp = *(SStruct)wParam;
delete pTemp;

Mike Stefanik
www.catalyst.com
Catalyst Development Corporation

John Syl.

Amazing how you think you understand something....then you find out how much you don't!! ???

That worked brilliantly..many thanks Mike.   ;D ;D ;D

John ;D
Intel 3.6 p4 ht, XP home,2 gb mem, 400 gb hd 20gb raid 0, Nvidia 6600le.
AMD k6-2 500, 40gb.

Started on PDP11 Assembler, BASIC, GWBASIC, 6502, Z80, 80x86, Java, Pascal, C, C++, 
IBasic (std & pro), Aurora, EBasic.  (Master of none, but it's been fun!)