In order that the GUI can function in parallel with the calling
application I construct a worker Tcl thread in the DLL and everything
is now fine until the caller application tries to close the GUI - the
GUI has no capability to close itself down.
I can delete the main window and the interpreters, then I call
Tcl_Finalize()which appears to complete correctly, however when the
caller program exits I'm left with an ConsoleWriterThread that's still
running.
I found a couple of old (version 8.3) posting here about the same
problem however I'm running 8.4.13 or 14
Does anyone know if this is still a problem?
Is it just a windows problem, or does it happen on other platforms?
Is there a known way to kill off this thread when I no longer want it?
Thanks,
Bernard
Windows rears its ugly head once more.. Tcl_Finalize() *should* have
shut it down for you. Start your deeper tracing from there.
--
David Gravereaux <davy...@pobox.com>
[species:human; planet:earth,milkyway(western spiral arm),alpha sector]
Are you Calling Tcl_Finalize from the same thread that started Tcl in
the first place? If not, you must that.
In the case of Tcl threads I have an initial interpreter which is in
thread A. This does in sequence:
Tcl_CreateInterp( parent )
Tcl_Init()
Tk_Init()
Tcl_CreateThread() - for thread B
In thread B there is:
Tcl_CreateInterp( child )
Tcl_Init()
Tk_Init()
Tk_MainLoop( child )
Tcl_DeleteInterp( child )
Tcl_FinalizeThread();
then finally, back in thread A there is:
Tcl_DeleteInterp( parent )
Tcl_Finalize( )
I checked and the Tcl thread ID's for the parent CreateInterp and the
last Finalize calls match.
If the issue is with the OS threads, do you know any way to positively
identify the calling thread?
Thanks,
Bernard
> I checked and the Tcl thread ID's for the parent CreateInterp and the
> last Finalize calls match.
Ok, you're good with that. Before Tcl_CreateInterp(), you might want to
call Tcl_FindExecutable as your first ever API call. Internally some
data is kept in thread specific structure and can be overlooked when the
initialer of Tcl isn't the closer.
Well, all I can say is that you need to hit the debugger and trace why
the console writer thread is not invoked to shutdown as it should have been.
If you're all GUI, there shouldn't be any console channel created, IIRC.
There's the console widget, but never is there the native console
channel type involved.
David,
Thanks for the feedback - there is a Tcl_FindExecutable - I left it out
of the (already long) description.
Can you please clarify "If you're all GUI, there shouldn't be any
console channel created" - do you mean "all GUI within the Tcl/Tk
environment"? We certainly don't open any I/O within Tcl/Tk, however
the parent application (we're running inside a DLL attached to another
application) will have both iostream and printf-based I/O and we have
some file I/O in a parser that's using in one of the registered
commands called from the GUI - the file is opened by our wrapper before
the GUI is built and closed after it should have been destoyed.
To try and resolve all this, I put a breakpoint on the console thread
at line 1216 in tclWinConsole.c - this is just inside:
static DWORD WINAPI ConsoleWriterThread(LPVOID arg)
The distrurbing thing is the breakpoint gets hit 4 times (I think that
means there are 4 threads?) but the 'break' at line 1233 only gets hit
twice. If I read the code right that means we've failed to delete 2
threads? Do you have an easy way to figure out what created these?
The stack trace unfortunately doesn't help because the thread is
independent of its parent by the time it hits my breakpoint.
Thanks,
Bernard
Having worked through the code and done lots of stepping, so far as I
can see there's a form linked list of channels maintained in the thread
specific data Each channel table contains a member nextCSPtr that
points to the previous table, so that the channels can be closed in
reverse order.
When I call Tcl_FinalizeThread() it eventually works it's way down
through CloseChannel() to Tcl_CutChannel(), where I find at line
2455 in generic/tclIO.c the code:
statePtr->nextCSPtr = (ChannelState *) NULL;
which breaks the link to the older channels and causes them not to be
signalled to close and therefore the threads don't get shut down.
The thing I'm puzzled about is why this line is here? Does anyone know
it's purpose? Does anyone know what else will break if I simply remove
it?
Thanks,
Bernard
berna...@yahoo.com wrote:
> When I call Tcl_FinalizeThread() it eventually works it's way down
> through CloseChannel() to Tcl_CutChannel(), where I find at line
> 2455 in generic/tclIO.c the code:
>
> statePtr->nextCSPtr = (ChannelState *) NULL;
>
> which breaks the link to the older channels and causes them not to be
> signalled to close and therefore the threads don't get shut down.
Excellent find. Please post a new Tcl bug report @
http://sourceforge.net/tracker/?func=add&group_id=10894&atid=110894 and
assign it to andreas_kupries with catagory #25
Don't let this go.. This is a good one. :)
I took another look at this, both in preparation for filing the bug
report and in the hope of making a quick fix myself, however I was
surprised how many calls are made to Tcl_CutChannel() - heck, it even
gets called in Tcl_FindExecutable()! I'm pretty sure that changing
this line will have some other unforseen impact but I wondered if
anyone can explain why there's so much manipulation of the channels,
and it there's anyway I can predict which should be allowed to break
the linked list / stack structure?
Thanks,
Bernard
The most effective way to get in touch with maintainers who can help on
these details is to file a bug report with as much good information as
you have.
--
| Don Porter Mathematical and Computational Sciences Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|______________________________________________________________________|