Hi All.running on my thread. Is there a reason why I would still be better off using CreateVOThread()?
I'm wondering if anyone knows what the differences between Win32 API CreateThread() vs. VO's CreateVOThread() are? Mostly with relation to the garbage collector. I.e. if I use Win32 API's CreateThread() would I completely avoid the garbage collector
I understand that threads and dynamic memory / the garbage collector don't play well together. I have in my ThreadFunc avoided declaring any LOCAL's and avoided calling any VO functions (because they might also have LOCAL's). There are also noanonymous variables like a string concatenation. Where I can't avoid a variable I use a structure (ThreadData) in static memory. The thread is the only reader/writer to this structure.
Assuming I haven't missed anything, my thread is only working in static memory and only calling Windows API functions.
The thread itself is pretty simple. It calls Win32 API IsHungAppWindow() once per second and logs an event in the windows event log if that function returns true.
I'm not sure how much I trust VO's threading (or my code not to have missed some dynamic memory allocation somewhere) so I've also included runtime options to completely disable this feature if it plays up.
Cheers!
Rob.
According to the docs the CreateThread() and CreateVOThread() are the same: However, "CreateVOThread() also performs some additional initializations
in the kernel runtime."
But it does not say what those initializations! But I guess it has to do with the GC suspension during its processing.
Additionally, the docs say (Just in case you did not see it and for others):
CreateVOThread() and ExitVOThread()
"First of all, threads in a Visual Objects application should not be
created by calling the Windows API function CreateThread() directly, but
by calling the Visual Objects runtime function CreateVOThread(). This function is called exactly like CreateThread() and actually it calls CreateThread() internally. CreateVOThread() also performs some
additional initializations in the kernel runtime.
Similar to CreateVOThread() there is an ExitVOThread() function that
should be called instead of ExitThread(). However, try to avoid exiting
a thread in a Visual Objects application by calling ExitThread() at all. Instead, exit your threads by returning from the thread entry point function."
And the docs go on further:
"When multiple threads are running, each dynamic memory pointer becomes
a shared resource. One thread might load a pointer to a string into a register. (The GC can only update memory locations, not registers.)
Before actually performing an operation with that pointer, execution is transferred to another thread that triggers the GC. Now the string
referred to by the register in the first thread is moved, and when
execution returns to the first thread, the pointer in the register is
not valid anymore."
"The problem described above will be resolved in a future release of
Visual Objects, but right now the programmer has to be aware of it."
(I don't think this was ever resolved, and I guess will never be)
"There are two ways of avoiding problems with threads and dynamic data.running on my thread. Is there a reason why I would still be better off using CreateVOThread()?
The first solution is to disable garbage collection when more than one thread is active and enabling it only again after all threads but one finish. This can be done through the Visual Objects runtime functions DynLock() and DynUnlock(). The disadvantage of this approach is that no
more memory will be freed or reused while the DynLock() is active.
Depending on the application logic, memory consumption might increase rapidly. Even when the collector runs again, the dynamic memory pool
will stay at the maximum size for future reuse. You might reduce the
size of the dynamic memory pool manually by calling DynShrink().
Disabling the collector globally while a thread is running, is a good solution when threads only run for a short while and do not generate a
lot of dynamic data garbage. Indexing a database produces a lot of
dynamic data garbage, so that indexing in a thread is not recommended
for bigger databases.
To avoid the collector problem, the solution is not to use dynamic data
at all inside a thread. Another solution is to minimize the use of
dynamic data to very few places, so that DynLock() and DynUnlock() can
be used locally. The Web server that will be presented later is a good example for this technique."
On 8/3/2021 6:56 AM, Robert Pope wrote:
Hi All.
I'm wondering if anyone knows what the differences between Win32 API CreateThread() vs. VO's CreateVOThread() are? Mostly with relation to the garbage collector. I.e. if I use Win32 API's CreateThread() would I completely avoid the garbage collector
anonymous variables like a string concatenation. Where I can't avoid a variable I use a structure (ThreadData) in static memory. The thread is the only reader/writer to this structure.I understand that threads and dynamic memory / the garbage collector don't play well together. I have in my ThreadFunc avoided declaring any LOCAL's and avoided calling any VO functions (because they might also have LOCAL's). There are also no
Assuming I haven't missed anything, my thread is only working in static memory and only calling Windows API functions.
The thread itself is pretty simple. It calls Win32 API IsHungAppWindow() once per second and logs an event in the windows event log if that function returns true.
I'm not sure how much I trust VO's threading (or my code not to have missed some dynamic memory allocation somewhere) so I've also included runtime options to completely disable this feature if it plays up.
Cheers!
Rob.
On Wednesday, August 4, 2021 at 2:05:19 AM UTC+10, Jamal wrote:running on my thread. Is there a reason why I would still be better off using CreateVOThread()?
According to the docs the CreateThread() and CreateVOThread() are the same: >> However, "CreateVOThread() also performs some additional initializations
in the kernel runtime."
But it does not say what those initializations! But I guess it has to do
with the GC suspension during its processing.
Additionally, the docs say (Just in case you did not see it and for others): >>
CreateVOThread() and ExitVOThread()
"First of all, threads in a Visual Objects application should not be
created by calling the Windows API function CreateThread() directly, but
by calling the Visual Objects runtime function CreateVOThread(). This
function is called exactly like CreateThread() and actually it calls
CreateThread() internally. CreateVOThread() also performs some
additional initializations in the kernel runtime.
Similar to CreateVOThread() there is an ExitVOThread() function that
should be called instead of ExitThread(). However, try to avoid exiting
a thread in a Visual Objects application by calling ExitThread() at all.
Instead, exit your threads by returning from the thread entry point
function."
And the docs go on further:
"When multiple threads are running, each dynamic memory pointer becomes
a shared resource. One thread might load a pointer to a string into a
register. (The GC can only update memory locations, not registers.)
Before actually performing an operation with that pointer, execution is
transferred to another thread that triggers the GC. Now the string
referred to by the register in the first thread is moved, and when
execution returns to the first thread, the pointer in the register is
not valid anymore."
"The problem described above will be resolved in a future release of
Visual Objects, but right now the programmer has to be aware of it."
(I don't think this was ever resolved, and I guess will never be)
"There are two ways of avoiding problems with threads and dynamic data.
The first solution is to disable garbage collection when more than one
thread is active and enabling it only again after all threads but one
finish. This can be done through the Visual Objects runtime functions
DynLock() and DynUnlock(). The disadvantage of this approach is that no
more memory will be freed or reused while the DynLock() is active.
Depending on the application logic, memory consumption might increase
rapidly. Even when the collector runs again, the dynamic memory pool
will stay at the maximum size for future reuse. You might reduce the
size of the dynamic memory pool manually by calling DynShrink().
Disabling the collector globally while a thread is running, is a good
solution when threads only run for a short while and do not generate a
lot of dynamic data garbage. Indexing a database produces a lot of
dynamic data garbage, so that indexing in a thread is not recommended
for bigger databases.
To avoid the collector problem, the solution is not to use dynamic data
at all inside a thread. Another solution is to minimize the use of
dynamic data to very few places, so that DynLock() and DynUnlock() can
be used locally. The Web server that will be presented later is a good
example for this technique."
On 8/3/2021 6:56 AM, Robert Pope wrote:
Hi All.
I'm wondering if anyone knows what the differences between Win32 API CreateThread() vs. VO's CreateVOThread() are? Mostly with relation to the garbage collector. I.e. if I use Win32 API's CreateThread() would I completely avoid the garbage collector
anonymous variables like a string concatenation. Where I can't avoid a variable I use a structure (ThreadData) in static memory. The thread is the only reader/writer to this structure.
I understand that threads and dynamic memory / the garbage collector don't play well together. I have in my ThreadFunc avoided declaring any LOCAL's and avoided calling any VO functions (because they might also have LOCAL's). There are also no
ideal in that regard. If VO doesn't know my second thread exists, hopefully the garbage collection would never initiate on it. Since the thread is using no dynamic memory it would be unaffected by the GC running on another (the main) thread concurrently.
Assuming I haven't missed anything, my thread is only working in static memory and only calling Windows API functions.
The thread itself is pretty simple. It calls Win32 API IsHungAppWindow() once per second and logs an event in the windows event log if that function returns true.
I'm not sure how much I trust VO's threading (or my code not to have missed some dynamic memory allocation somewhere) so I've also included runtime options to completely disable this feature if it plays up.
Cheers!
Rob.
Thanks for replying.
I have seen that documentation / white paper.
In my case locking dynamic memory isn't an option. The thread continues for the lifetime of the application, and this isn't a small application. So yeah, as per my original post, my approach is to avoid using dynamic memory at all in the thread.
What I really hope is that the garbage collector would only ever be called from the main thread. I don't want the worker thread to start the GC. Hence why I'm hoping that calling the Windows API's CreateThread() over VO's CreateVOThread() might be more
I guess I'm hoping that someone with internal knowledge of VO threading might still be lurking around these parts to provide some undocumented knowledge. :)
Cheers.
If VO doesn't know my second thread exists, hopefully the garbage
collection would never initiate on it. Since the thread is using no
dynamic memory it would be unaffected by the GC running on
another (the main) thread concurrently.
On Wednesday, August 4, 2021 at 2:05:19 AM UTC+10, Jamal wrote:
According to the docs the CreateThread() and CreateVOThread() are
the same: However, "CreateVOThread() also performs some additional initializations in the kernel runtime."
But it does not say what those initializations! But I guess it has
to do with the GC suspension during its processing.
Additionally, the docs say (Just in case you did not see it and for others):
CreateVOThread() and ExitVOThread()
"First of all, threads in a Visual Objects application should not
be created by calling the Windows API function CreateThread()
directly, but by calling the Visual Objects runtime function CreateVOThread(). This function is called exactly like
CreateThread() and actually it calls CreateThread() internally. CreateVOThread() also performs some additional initializations in
the kernel runtime.
Similar to CreateVOThread() there is an ExitVOThread() function
that should be called instead of ExitThread(). However, try to
avoid exiting a thread in a Visual Objects application by calling ExitThread() at all. Instead, exit your threads by returning from
the thread entry point function."
And the docs go on further:
"When multiple threads are running, each dynamic memory pointer
becomes a shared resource. One thread might load a pointer to a
string into a register. (The GC can only update memory locations,
not registers.) Before actually performing an operation with that
pointer, execution is transferred to another thread that triggers
the GC. Now the string referred to by the register in the first
thread is moved, and when execution returns to the first thread,
the pointer in the register is not valid anymore."
"The problem described above will be resolved in a future release
of Visual Objects, but right now the programmer has to be aware of
it."
(I don't think this was ever resolved, and I guess will never be)
"There are two ways of avoiding problems with threads and dynamic
data. The first solution is to disable garbage collection when
more than one thread is active and enabling it only again after all
threads but one finish. This can be done through the Visual Objects
runtime functions DynLock() and DynUnlock(). The disadvantage of
this approach is that no more memory will be freed or reused while
the DynLock() is active. Depending on the application logic,
memory consumption might increase rapidly. Even when the collector
runs again, the dynamic memory pool will stay at the maximum size
for future reuse. You might reduce the size of the dynamic memory
pool manually by calling DynShrink().
Disabling the collector globally while a thread is running, is a
good solution when threads only run for a short while and do not
generate a lot of dynamic data garbage. Indexing a database
produces a lot of dynamic data garbage, so that indexing in a
thread is not recommended for bigger databases.
To avoid the collector problem, the solution is not to use dynamic
data at all inside a thread. Another solution is to minimize the
use of dynamic data to very few places, so that DynLock() and
DynUnlock() can be used locally. The Web server that will be
presented later is a good example for this technique."
On 8/3/2021 6:56 AM, Robert Pope wrote:
Hi All.
I'm wondering if anyone knows what the differences between Win32
API CreateThread() vs. VO's CreateVOThread() are? Mostly with
relation to the garbage collector. I.e. if I use Win32 API's CreateThread() would I completely avoid the garbage collector
running on my thread. Is there a reason why I would still be
better off using CreateVOThread()?
I understand that threads and dynamic memory / the garbage
collector don't play well together. I have in my ThreadFunc
avoided declaring any LOCAL's and avoided calling any VO
functions (because they might also have LOCAL's). There are also
no anonymous variables like a string concatenation. Where I can't
avoid a variable I use a structure (ThreadData) in static memory.
The thread is the only reader/writer to this structure.
Assuming I haven't missed anything, my thread is only working in
static memory and only calling Windows API functions.
The thread itself is pretty simple. It calls Win32 API
IsHungAppWindow() once per second and logs an event in the
windows event log if that function returns true.
I'm not sure how much I trust VO's threading (or my code not to
have missed some dynamic memory allocation somewhere) so I've
also included runtime options to completely disable this feature
if it plays up.
Cheers!
Rob.
Thanks for replying.
I have seen that documentation / white paper.
In my case locking dynamic memory isn't an option. The thread
continues for the lifetime of the application, and this isn't a small application. So yeah, as per my original post, my approach is to
avoid using dynamic memory at all in the thread.
What I really hope is that the garbage collector would only ever be
called from the main thread. I don't want the worker thread to start
the GC. Hence why I'm hoping that calling the Windows API's
CreateThread() over VO's CreateVOThread() might be more ideal in that
regard. If VO doesn't know my second thread exists, hopefully the
garbage collection would never initiate on it. Since the thread is
using no dynamic memory it would be unaffected by the GC running on
another (the main) thread concurrently.
I guess I'm hoping that someone with internal knowledge of VO
threading might still be lurking around these parts to provide some undocumented knowledge. :)
Cheers.
Hi Robert,
please be aware that you cannot use any VO specific datatype in the
thread like strings, floats or objects because they are collected when
not used.
I would strongly recommend to no use threads in a VO application, and
use rather a second application instead of a second thread linked by
some collaboration mechanism.
Or you may have another alternative: use X# instead. In X# not only the garbage collector is thread safe, but also the RDDs if you need them.
Wolfgang
Robert Pope wrote:
On Wednesday, August 4, 2021 at 2:05:19 AM UTC+10, Jamal wrote:
According to the docs the CreateThread() and CreateVOThread() are
the same: However, "CreateVOThread() also performs some additional initializations in the kernel runtime."
But it does not say what those initializations! But I guess it has
to do with the GC suspension during its processing.
Additionally, the docs say (Just in case you did not see it and for others):
CreateVOThread() and ExitVOThread()
"First of all, threads in a Visual Objects application should not
be created by calling the Windows API function CreateThread()
directly, but by calling the Visual Objects runtime function CreateVOThread(). This function is called exactly like
CreateThread() and actually it calls CreateThread() internally. CreateVOThread() also performs some additional initializations in
the kernel runtime.
Similar to CreateVOThread() there is an ExitVOThread() function
that should be called instead of ExitThread(). However, try to
avoid exiting a thread in a Visual Objects application by calling ExitThread() at all. Instead, exit your threads by returning from
the thread entry point function."
And the docs go on further:
"When multiple threads are running, each dynamic memory pointer
becomes a shared resource. One thread might load a pointer to a
string into a register. (The GC can only update memory locations,
not registers.) Before actually performing an operation with that pointer, execution is transferred to another thread that triggers
the GC. Now the string referred to by the register in the first
thread is moved, and when execution returns to the first thread,
the pointer in the register is not valid anymore."
"The problem described above will be resolved in a future release
of Visual Objects, but right now the programmer has to be aware of
it."
(I don't think this was ever resolved, and I guess will never be)
"There are two ways of avoiding problems with threads and dynamic
data. The first solution is to disable garbage collection when
more than one thread is active and enabling it only again after all threads but one finish. This can be done through the Visual Objects runtime functions DynLock() and DynUnlock(). The disadvantage of
this approach is that no more memory will be freed or reused while
the DynLock() is active. Depending on the application logic,
memory consumption might increase rapidly. Even when the collector
runs again, the dynamic memory pool will stay at the maximum size
for future reuse. You might reduce the size of the dynamic memory
pool manually by calling DynShrink().
Disabling the collector globally while a thread is running, is a
good solution when threads only run for a short while and do not
generate a lot of dynamic data garbage. Indexing a database
produces a lot of dynamic data garbage, so that indexing in a
thread is not recommended for bigger databases.
To avoid the collector problem, the solution is not to use dynamic
data at all inside a thread. Another solution is to minimize the
use of dynamic data to very few places, so that DynLock() and
DynUnlock() can be used locally. The Web server that will be
presented later is a good example for this technique."
On 8/3/2021 6:56 AM, Robert Pope wrote:
Hi All.
I'm wondering if anyone knows what the differences between Win32
API CreateThread() vs. VO's CreateVOThread() are? Mostly with
relation to the garbage collector. I.e. if I use Win32 API's CreateThread() would I completely avoid the garbage collector
running on my thread. Is there a reason why I would still be
better off using CreateVOThread()?
I understand that threads and dynamic memory / the garbage
collector don't play well together. I have in my ThreadFunc
avoided declaring any LOCAL's and avoided calling any VO
functions (because they might also have LOCAL's). There are also
no anonymous variables like a string concatenation. Where I can't
avoid a variable I use a structure (ThreadData) in static memory.
The thread is the only reader/writer to this structure.
Assuming I haven't missed anything, my thread is only working in
static memory and only calling Windows API functions.
The thread itself is pretty simple. It calls Win32 API IsHungAppWindow() once per second and logs an event in the
windows event log if that function returns true.
I'm not sure how much I trust VO's threading (or my code not to
have missed some dynamic memory allocation somewhere) so I've
also included runtime options to completely disable this feature
if it plays up.
Cheers!
Rob.
Thanks for replying.
I have seen that documentation / white paper.
In my case locking dynamic memory isn't an option. The thread
continues for the lifetime of the application, and this isn't a small application. So yeah, as per my original post, my approach is to
avoid using dynamic memory at all in the thread.
What I really hope is that the garbage collector would only ever be
called from the main thread. I don't want the worker thread to start
the GC. Hence why I'm hoping that calling the Windows API's
CreateThread() over VO's CreateVOThread() might be more ideal in that regard. If VO doesn't know my second thread exists, hopefully the
garbage collection would never initiate on it. Since the thread is
using no dynamic memory it would be unaffected by the GC running on
another (the main) thread concurrently.
I guess I'm hoping that someone with internal knowledge of VO
threading might still be lurking around these parts to provide some undocumented knowledge. :)
Cheers.--
I guess I will post the code of my thread func, given the responses
I'm getting :) And the question I'm trying to have answered: Would
the garbage collector ever initiate on this thread if I start it with CreateThread()? I don't want it to.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 293 |
Nodes: | 16 (2 / 14) |
Uptime: | 216:46:57 |
Calls: | 6,621 |
Calls today: | 3 |
Files: | 12,169 |
Messages: | 5,317,616 |