LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

SetCtrlVal used during Thread Function is working causes memory leaks

Solved!
Go to solution

I am writing a program which works if... Or works not if...  - see the next lines... 🙂 ...

 

The program has one part, mainly GUI- and User-Interaction.

The other part is a DLL. In the DLL there are readouts over RS232 from a external controller-board. Sometimes the controller-board needs some time (known how much) and this time must pass by then the result can be read out from the controller board ... and so on ...

By not blocking the GUI-User-Program for waiting the return-value of the the DLL-functions (which need some seconds to be finished) I start in the DLL a thread with

 

CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE, THREAD_FunctionX, &tmpTFP, NULL);

 

with "tmpTFP" as a type-instance of "TYPE_THREAD_FUNCTION_PARAMETERS":

typedef struct
{
    //
    int IntVal1;                // 1. Integer-Wert
    int IntVal2;                // 2. Integer-Wert
    int IntVal3;                // 3. Integer-Wert
    int IntVal4;                // 4. Integer-Wert
    int IntVal5;                // 5. Integer-Wert
    //
    int IntBuffer1[32];            // 1. Integer-Buffer (aktuell genügt einer)
    //
    double DblVal1;                // 1. Double-Wert
    double DblVal2;                // 2. Double-Wert
    double DblVal3;                // 3. Double-Wert
    double DblVal4;                // 4. Double-Wert
    double DblVal5;                // 5. Double-Wert
    //
    char CharVal1;                // 1. (Einzel-)Char-Wert
    char CharVal2;                // 2. (Einzel-)Char-Wert
    char CharVal3;                // 3. (Einzel-)Char-Wert
    char CharVal4;                // 4. (Einzel-)Char-Wert
    char CharVal5;                // 5. (Einzel-)Char-Wert
    //
    char CharBuffer1[1024];        // 1. Char-Buffer (akutell genügt einer)
    //
} TYPE_THREAD_FUNCTION_PARAMETERS;

In the GUI-User-Program I get quick a default-return-value of the thread-starting function.

Then I poll the DLL (some global state-variables are used for that) when it is finished.

Depending on the contacted (RS232) controller-board the waiting time depends on the "mood" of the controller-board.

 

In the DLL-polling-routine of the GUI-User-Program now everything is working fine - without using "SetCtrlVal" !

 

In my GUI there is a info/comment text-box for messages. If I make some User-Outputs by using "SetCtrlVal" I get always errors, caused by wrong "TYPE_THREAD_FUNCTION_PARAMETERS"-values in the thread-function. If I set a break-point at the thread-function start I see mostly false values in my transfer-structure-variables. If I set a break-point at the thread-function-caller "CmtScheduleThreadPoolFunction(...)" and at the beginning of the thread the values are (mostly) correct!

 

I tried many and different things - but:

If I  ONLY (!)  commenting out the one (!) line with "SetCtrlVal" the program works, all states are polled well out of the DLL.

If I replace the "SetCtrlVal" with a own written logging-file function everything works fine and after the program finished I can watch the log-file and see all user-info's. BUT with "SetCtrlVal" instead or together or (...) it does not work.

 

Maybe my description is not totaly clear, but believe me: ONLY ONE line - the "SetCtrlVal"-line - must be comented out to let the program work fine!

Because if the "SetCtrlVal"-line is in GUI-User-program, after the thread-call in the DLL, the DLL-Memory seems to be corrupted by the "SetCtrlVal"-Call in the GUI-User-program.

 

Best regards,

F.

 

0 Kudos
Message 1 of 11
(5,399 Views)

Additional:

 

Now I changed the GUI-User-program that the info-message is send to the GUI before the DLL-thread starts. Now the memory-leak-error does not any longer happen!


But if I use the former version - the GUI-message is presented in the GUI after and during (!) the DLL-thread is working - there occurs (anywhere in "SetCtrlVal") a memory leak and the function-parametes of the DLL-thread are corrupted (because they get arbitrary values).

 

This is not a real solution more a workaround - what if someone will "dare" to use "SetCtrlVal" during a DLL-function is still working?

My application is not the only thinkable use case, more interesting would be if the thread function is doing some calculations for graphics or video for example...

What happens then - the same as in my threaded application?

And is "SetCtrlVal" ist not the only LabWindows-CVI GUI-function which causes these problems: I testet also it's "brother"-function "SetCtrlAttribute", which causes the same problem... and if there are two... there are more...

 

Regards,

F.

 

0 Kudos
Message 2 of 11
(5,401 Views)

Eve if you have added several details, it seems the most useful informations are missing here:

 

1. Do you prepare someway the structured variable at program start? Otherwise it will have garbage in it until the DLL function (which I suppose is in charge of filling the fileds) is finished

2. What are you displaying in the text box message? The content of CharBuffer1 fied or some message formatted out of numeric values in the struct?

3. Can you add the lines which you use to display the messages, including the preparation lines (sprintf, Fmt, FormatMessage or whichever function you are using)?

4. If the long-lasting DLL function produces result at its end, does it make sense to display informations before this moment? If yes, then you should prepare fileds to avoid problems in displaying (see item #1 in the list). An alternative could be to simply wait for logging until the process ends



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 3 of 11
(5,394 Views)

Additionally, why are you speaking about a memory leak? Did you observe some increment in dynamic memory occupation or have some other synptom of a memory leak?



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
Message 4 of 11
(5,391 Views)

First of all:

I missunderstood the word-combination "memory leak". According to wikipedia a "memory leak" is the effect that a program occupies more and more memory. By that meaning is "leaking" that the free computer memory becomes less, or in other words the program "floads" the memory ... ?

But that is the official meaning of that word combination an I was wrong. So the word-combination "memory leak" in the title must be repalced with "memory overwrite" - which I did in my reply.

 

Second:

1.

My thread-caller fuction initializes an instance

        "TYPE_THREAD_FUNCTION_PARAMETERS tmpTFP = {0};"

and short after that line a breakpoint shows in debug-mode that there are all "0" in all structure-components.

Close to the end of the thread-caller function the values I need are set in "tmpTFP" such as

        "tmpTFP.CharVal1 = TheIntVariable;"

with "TheIntVariable" as a parameter variable of the thread-caller fuction.

And directly after all these settings I evoke the thread it self with

        "CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE, nameXYZ_THREAD, &tmpTFP, NULL);"

and I leave the thread caller-function which name is "nameXYZ" - without the "_THREAD" at it's end.

Till that leaving in "tmpTFP" are all values as I want or as they are inizialized ("0").

The thread function

        "int CVICALLBACK nameXYZ_THREAD(TYPE_THREAD_FUNCTION_PARAMETERS *ptr_FunctionData)"

is now evoked and a breakpoint directly after the function header shows in "ptr_FunctionData" the wrong values or the right values - depending on the mentioned topic on top of this page.

In my DLL there are the functions:

         "nameXYZ_THREAD" (the thread function) and "int __stdcall nameXYZ" (the thread caller function).

In my DLL-using GUI-User-Program there is a universal DLL-polling-function

         "WaitAndGetDllThreadResponse"

with a parameter "SecsToTimeout" to avoid infinite wait-loops and the return-value as the return-value of the DLL-thread function "nameXYZ_THREAD" wich is get out of a global 'data-save'-structure in the DLL. In "WaitAndGetDllThreadResponse" there is a loop with "SecsToTimeout" as 'emergency break' and a DLL-state poll function "DLL_Get_BusyState" which returns a integer-value of the global 'data-save'-structure in the DLL --> "0": DLL is not busy and "1": DLL is busy (with a thread). The "DLL-Busy-State" is set "1" in the thread-caller function and "0" at the (absolute) end of the thread-function.The return-value of the thread-function is not evaluate and I did not know how it could be evaluated ... or should be ...?... whatever!

 

2.

I display in the text-box message only text-informations which are generated in the GUI-User program and without any values of the DLL.

 

3.

In the display-function of the GUI-User program I tried a few things as the following:

  (a)   "SetCtrlVal(g_panelMain, PCMT_PANEL_TEXTMSG, InfoTextDuringWaitAndGet);" with "InfoTextDuringWaitAndGet" as a input-string of the "WaitAndGetDllThreadResponse"-function

  (b)   "sprintf(tmpTxt, "%s ", InfoTextDuringWaitAndGet);" and

         "SetCtrlVal(g_panelMain, PCMT_PANEL_TEXTMSG, tmpTxt);"

  (c)  The two forms above with "ProcessDrawEvents" and "ProcessSystemEvents" after the "SetCtrlVal" and without.

 

But whatever: If I only comment out the "SetCtrlVal"-line the program works fine and if I let it in the program produces garbage.

That means the values of "ptr_FunctionData" in the DLL-thread function are corrupted with "SetCtrlVal" in the non-DLL-related GUI-User-program!

So, the memory of the DLL is corrupted by using "SetCtrlVal" not in the DLL - a bit freaky!

 

4.

My actual "remedy" is to do the "SetCtrlVal" before I call the DLL-thread-caller function in the GUI-User-program.

If I do the "SetCtrlVal" direct after calling the DLL-thread-caller function either in a separate display-function (in the GUI-User-program, not a DLL-function!) or 'explicite' as spearate "SetCtrlVal"-line, always the memory overwrite will happen!

 

Maybe an other remedy would be that I use in the DLL-function for the thread-caller and the thread itself a global instance of the structure-type "TYPE_THREAD_FUNCTION_PARAMETERS". Maybe, with that the DLL-memory is not corrupted ... but I did'nt test that (until now, maybe I will in future?).

 

==> Conclusion:

       The DLL-memory is corrupted or overwritten by a "SetCtrlVal"-call in the GUI-User-function meanwhile in the DLL is running a thread-function.

 

0 Kudos
Message 5 of 11
(5,363 Views)

I made the other "approach":

      A 'general' global from type "TYPE_THREAD_FUNCTION_PARAMETERS", used in the DLL.

 

This global "TYPE_THREAD_FUNCTION_PARAMETERS" structure variable ("g_tmpTFP") solves the problem.

 

Juhu (but a not very convinced juhu) !

 

I need a DLL-project global variable to solve the following problem:

     The thread-function parameter structure variable inside a DLL is destroyed or overwritten

     by a GUI-message-box interaction in the DLL-calling GUI-User-program. - Wow!

 

If there would be "side-effect" like this inside a single project - this would make some sense (for me).

But one program (EXE) has an memory-effect to an other (seemingly independent) program (DLL) this is a bit hard.

I think the reason is inside the runtime:

The programmers thread-function is using some functionality inside the runtime, which is also used by the built-in GUI-function "SetCtrlVal".

Thus, if the programmer evokes a thread in the DLL and short afterwards he makes a "SetCtrlVal"-call in the EXE, inside the LabWin-Runtime there seems to be only one temporary "space" for the parameter-pointer or it's data and therefore the first dependency/content is lost and only the second (of the "SetCtrlVal"-operation) is available.

    ==> Threading must be used very carefully if there are GUI-outputs or interactions are done!

 

0 Kudos
Message 6 of 11
(5,352 Views)
Solution
Accepted by topic author FrankieBoy98

There may be a problem in your structure depending on where your variable is defined.

You said that after you pass the address of the variable to the thread function the caller one terminates. Now, as you can read in the help every value passed in threadFunctionData parameter of the spawned function must point to a  memory area that persist when the fuction is in execution: if your variable is defined at function-level it will not be valid when the thread executes since the caller has terminated and released its local memory.

Your approach with a global variable is a valid alternative, but whichever is the solution you find data passed to the thread function must be valid throughout its life.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
Message 7 of 11
(5,335 Views)

Thank you - now it is obvious but not absolutely clear why it works without "SetCtrlVal".

 

I didn't read the help that exactly, because before I added a screen-info-message, with "SetCtrlVal", the program was running correctly. And I thought that I use the thread-caller correctly. As I see now, this was only some sort of "luck", or for me more "bad luck", because if I had that sort of errors from the beginning, I wouldn't be that convinced that I use the thread-function call correctly. The local, supposed not longer existing, variable still exists, if no other thread or thread-like process occours in the beginning of the thread-function. Because I use a lot of threads, in my DLL, all in the same scheme and all called in a sequence in the GUI-User-program, in a way that they do not interfere themselves . And they all work correctly, if they are not interrupted by "SetCtrlVal", or an other command/function which has obviously effect on the thread parameter-pointer or the thread handling itself.

 

But whatever it is, the runtime, a general "bug" or my own programming, I have to adopt my own program - if it should run Smiley Wink - and it should!

0 Kudos
Message 8 of 11
(5,323 Views)
Solution
Accepted by topic author FrankieBoy98

...by the way: I talked with a "visual studio programmer" about the destruction of the thread-parameter pointer in LabWindows/CVI and he was very surprised about that and he said he also would expect that the to the thread given parameter pointer and it's memory would exist as long as that thread is runing... now I am not longer surprised about that, because my original expectation about that pointer/memory is not "unusual" or "unapologetic".

 

Greetings,

F.

 

0 Kudos
Message 9 of 11
(5,274 Views)

What you have to realize is that, like all callback data, the &tmpTFp parameter that you pass to the CmtScheduleThreadPoolFunction is only a pointer reference to your data. It is not the data itself. The CmtScheduleThreadPoolFunction does not create a copy of the data object that that pointer points to. Nor could it even it wanted to, since it doesn't know what kind of object, or how large, tmpTFp might be. All the function knows is the 4-byte void pointer that you pass to it.

 

As a matter of fact, if you look at the help of the Thread Function Data parameter, you'll see a sentence that explicitly warns you about this scenario: "Do not pass the address of a local variable or any other variable that might not be valid when the function is executed". If the original data is destroyed while the thread function is still executing, then your reference to the data in the thread funcion becomes invalid.

 

Luis

Message 10 of 11
(5,253 Views)