Rocksolid Light

Welcome to RetroBBS

mail  files  register  newsreader  groups  login

Message-ID:  

E = MC ** 2 +- 3db


devel / comp.lang.clipper.visual-objects / Re: CreateThread vs. CreateVOThread

Re: CreateThread vs. CreateVOThread

<e6812d0d-4359-4ab8-8844-bf4c8ad7a064n@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=908&group=comp.lang.clipper.visual-objects#908

  copy link   Newsgroups: comp.lang.clipper.visual-objects
X-Received: by 2002:a37:96c2:: with SMTP id y185mr513783qkd.6.1628097487386; Wed, 04 Aug 2021 10:18:07 -0700 (PDT)
X-Received: by 2002:a37:994:: with SMTP id 142mr438811qkj.277.1628097487139; Wed, 04 Aug 2021 10:18:07 -0700 (PDT)
Path: i2pn2.org!i2pn.org!news.swapon.de!news.uzoreto.com!tr1.eu1.usenetexpress.com!feeder.usenetexpress.com!tr3.iad1.usenetexpress.com!border1.nntp.dca1.giganews.com!nntp.giganews.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.clipper.visual-objects
Date: Wed, 4 Aug 2021 10:18:06 -0700 (PDT)
In-Reply-To: <imvoouFss3fU1@mid.individual.net>
Injection-Info: google-groups.googlegroups.com; posting-host=103.20.253.4; posting-account=zmD_sgoAAAAcgEYSDqXDAKJk2oQcCwKt
NNTP-Posting-Host: 103.20.253.4
References: <29915aac-da35-4455-b403-c1fec00692e3n@googlegroups.com> <sebpfl$vn7$1@gioia.aioe.org> <9405fc40-7ecc-44e1-a60c-dd57eb1242f0n@googlegroups.com> <imvoouFss3fU1@mid.individual.net>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <e6812d0d-4359-4ab8-8844-bf4c8ad7a064n@googlegroups.com>
Subject: Re: CreateThread vs. CreateVOThread
From: cooeee@gmail.com (Robert Pope)
Injection-Date: Wed, 04 Aug 2021 17:18:07 +0000
Content-Type: text/plain; charset="UTF-8"
Lines: 233
 by: Robert Pope - Wed, 4 Aug 2021 17:18 UTC

On Thursday, August 5, 2021 at 1:07:12 AM UTC+10, Wolfgang Riedmann wrote:
> 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.

STRUCT HeartBeatMonitor_ThreadData

MEMBER hWnd AS PTR
MEMBER hEventSource AS PTR
MEMBER pszEventSource AS PSZ
MEMBER RootDirectory AS PSZ
MEMBER sTimeStart AS _winSYSTEMTIME
MEMBER sTimeEnd AS _winSYSTEMTIME

FUNCTION HeartbeatMonitor(sHeartBeatMonitor_ThreadData AS HeartBeatMonitor_ThreadData) AS DWORD PASCAL

// Do not declare any locals here. Garbage collector is not thread safe.
// Also must not call any functions including VO builtins that might allocate memory.

DO WHILE TRUE
IF sHeartBeatMonitor_ThreadData.hWnd != NULL_PTR

IF IsHungAppWindow(sHeartBeatMonitor_ThreadData.hWnd)
IF sHeartBeatMonitor_ThreadData.sTimeStart == NULL_PTR

sHeartBeatMonitor_ThreadData.sTimeStart := MemAlloc(_SizeOf(_winSYSTEMTIME))
GetLocalTime(sHeartBeatMonitor_ThreadData.sTimeStart)

sHeartBeatMonitor_ThreadData.hEventSource := RegisterEventSource(NULL_PSZ, sHeartBeatMonitor_ThreadData.pszEventSource)
ReportEvent(sHeartBeatMonitor_ThreadData.hEventSource, EVENTLOG_WARNING_TYPE, 0, MSG_APPLICATION_HANG, NULL_PTR, 1, 0, @sHeartBeatMonitor_ThreadData.RootDirectory, NULL_PTR)
DeregisterEventSource(sHeartBeatMonitor_ThreadData.hEventSource)
sHeartBeatMonitor_ThreadData.hEventSource := NULL_PTR

END IF
ELSE
IF sHeartBeatMonitor_ThreadData.sTimeStart != NULL_PTR

sHeartBeatMonitor_ThreadData.sTimeEnd := MemAlloc(_SizeOf(_winSYSTEMTIME))
GetLocalTime(sHeartBeatMonitor_ThreadData.sTimeEnd)

sHeartBeatMonitor_ThreadData.hEventSource := RegisterEventSource(NULL_PSZ, sHeartBeatMonitor_ThreadData.pszEventSource)
ReportEvent(sHeartBeatMonitor_ThreadData.hEventSource, EVENTLOG_INFORMATION_TYPE, 0, MSG_APPLICATION_RESUME, NULL_PTR, 1, 0, @sHeartBeatMonitor_ThreadData.RootDirectory, NULL_PTR)
DeregisterEventSource(sHeartBeatMonitor_ThreadData.hEventSource)
sHeartBeatMonitor_ThreadData.hEventSource := NULL_PTR

MemFree(sHeartBeatMonitor_ThreadData.sTimeStart)
MemFree(sHeartBeatMonitor_ThreadData.sTimeEnd)

sHeartBeatMonitor_ThreadData.sTimeStart := NULL_PTR
sHeartBeatMonitor_ThreadData.sTimeEnd := NULL_PTR

END IF
END IF

END IF

Sleep(1000)

END DO

RETURN 0

This function runs on the main thread to launch the thread:
FUNCTION HeartbeatMonitorInit(hWnd AS PTR) AS VOID PASCAL

LOCAL sSECURITY_ATTRIBUTES AS _winSECURITY_ATTRIBUTES
LOCAL sHeartBeatMonitor_ThreadData AS HeartBeatMonitor_ThreadData
sSECURITY_ATTRIBUTES := MemAlloc(_SizeOf(_winSECURITY_ATTRIBUTES))
sSECURITY_ATTRIBUTES.nLength := _SizeOf(_winSECURITY_ATTRIBUTES)
sSECURITY_ATTRIBUTES.lpSecurityDescriptor := NULL_PTR
sSECURITY_ATTRIBUTES.bInheritHandle := FALSE
sHeartBeatMonitor_ThreadData := MemAlloc(_SizeOf(HeartBeatMonitor_ThreadData))
sHeartBeatMonitor_ThreadData.hWnd := hWnd
sHeartBeatMonitor_ThreadData.pszEventSource := PszAlloc(String2PSZ("XXXXX"))
sHeartBeatMonitor_ThreadData.RootDirectory := PszAlloc(String2PSZ(gcRootDirectory))
sHeartBeatMonitor_ThreadData.sTimeStart := NULL_PTR
sHeartBeatMonitor_ThreadData.sTimeEnd := NULL_PTR

CreateThread(sSECURITY_ATTRIBUTES, 0, @HeartbeatMonitor(), sHeartBeatMonitor_ThreadData, 0, NULL_PTR)
MemFree(sSECURITY_ATTRIBUTES)

RETURN

Cheers!

SubjectRepliesAuthor
o CreateThread vs. CreateVOThread

By: Robert Pope on Tue, 3 Aug 2021

7Robert Pope
server_pubkey.txt

rocksolid light 0.9.81
clearnet tor