[Home] [Downloads] [Search] [Help/forum]

Gammon Forum

See www.mushclient.com/spam for dealing with forum spam. Please read the MUSHclient FAQ!

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  General
. . -> [Subject]  Threading problems.
Home  |  Users  |  Search  |  FAQ
Username:
Register forum user name
Password:
Forgotten password?

Threading problems.

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page


Posted by Mudguy   (4 posts)  [Biography] bio
Date Wed 10 Aug 2005 04:23 PM (UTC)
Message
Let's take this Python script, timer.py:

from time import clock
import threading

def sleep(num, func, test, args):
    fire = clock() + num
    while clock() < fire:
        if not test():
            return
    func(*args)

def balance(num, func, test, args = [], tar = sleep):
    t = threading.Thread(target = tar, kwargs = locals())
    t.start()


and a plugin:

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Thursday, July 21, 2005, 9:57 PM -->
<!-- MuClient version 3.66 -->


<muclient>
<plugin
   name="Bazzinator"
   author="mudguy"
   id="bd3b5b5ec7994dc41dfbd2ca"
   language="Python"
   purpose="To bazzinate the foobar"
   save_state="y"
   date_written="2005-07-21 21:57:00"
   requires="3.66"
   >

</plugin>


<!--  Get our standard constants -->

<include name="constants.pys"/>


<!--  Script  -->


<script>
<![CDATA[
import timer

def foo():
    timer.balance(10, baz, bar)

def bar():
    return True

def baz():
    world.Note('Done!')
]]>
</script>


</muclient>


Now, when I run this, it chugs along fine for the 10 seconds while the thread runs, but as soon as it calls baz Windows tells me that MUSHclient 'has run into problems and must be shut down'. This is decidedly weird, since with the send details box open, I can still input commands to MUSHclient and receive lines from the server back. If someone tells me how to extract the information provided by this dialogue box (some DLLs referenced and a hex dump, I think), I can provide that as well, but as it is now I can only look at it and not copy it. This is on XP Professional, SP 2, with MUSHclient 3.66.

I know this can be done with MUSHclient timers instead, but I'm planning to expand this to things that can't be done with those.

So what am I doing wrong? Or how can I work around this problem?
[Go to top] top

Posted by David Haley   USA  (3,881 posts)  [Biography] bio
Date Reply #1 on Wed 10 Aug 2005 04:52 PM (UTC)
Message
Well, this would depend on whether or not MUSHclient expects plugins to come along at random times and make API calls - in other words, it has to be thread-safe and all that. Nick's the only one who would know that for sure.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
[Go to top] top

Posted by Larkin   (278 posts)  [Biography] bio
Date Reply #2 on Wed 10 Aug 2005 06:47 PM (UTC)
Message
Why not just use MUSHclient's timers, since that appears to be what you're (re)implementing with your thread?
[Go to top] top

Posted by Mudguy   (4 posts)  [Biography] bio
Date Reply #3 on Wed 10 Aug 2005 08:40 PM (UTC)
Message
As I said in the oriinal post, this is going to be extended further into something that MUSHclitn timers can't deal with. One thing to be done is to give MUSHclient access to page scraping and news feeds, removing all the tiresome window swapping and pushing of F5. Along this thread (excuse the pun), MUSHclient could also be given Instant Messaging capacity. Other large tasks that are too long to be done linearly and would need to call the API are also possible.
[Go to top] top

Posted by David Haley   USA  (3,881 posts)  [Biography] bio
Date Reply #4 on Wed 10 Aug 2005 08:47 PM (UTC)
Message
Are you basically aiming to turn MUSHclient into a centralized information repository of sorts? A MUD client that also hooks into feeds, news pages, instant messaging, etc.?

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
[Go to top] top

Posted by Ked   Russia  (524 posts)  [Biography] bio
Date Reply #5 on Sat 13 Aug 2005 05:27 AM (UTC)
Message
The solution to this exists, though you have to know where to look for it. You should look at Python/Lib/site-packages/win32com/test/testMarshall.py for firsthand example, but here's a snippet that's a bit simpler:


import thread, pythoncom
from time import sleep
from win32com.client import Dispatch

class Ticker(object):
    def __init__(self, func, world):
        self.keep_alive = False
        self.interval = 0.1
        self.lock = thread.allocate_lock()
        if callable(func):
            self.func = func
        else:
            raise Error, "Argument passed to the Ticker class must be a callable object, got %s instead." % str(type(func))

        if world:
            self.mc = Dispatch(world)
        else:
            self.mc = None
            
        
    def start(self):
        #Marshal the caller object ('World' ref dispatched above) so it can be passed into the timer thread
        stream = pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch, self.mc._oleobj_)
        #start timer thread using the Run method and passing the marshaled stream object to it

        self.keep_alive = True
        thread.start_new_thread(self.run, (stream,))

    def run(self, stream):
        #COM must be initialized manually in secondary threads
        pythoncom.CoInitialize()
        #extract the World interface from stream and release the latter
        caller = pythoncom.CoGetInterfaceAndReleaseStream(stream, pythoncom.IID_IDispatch)
        world = Dispatch(caller)  #caller is dispatched in this thread's context now

        while self.keep_alive:
            self.lock.acquire()
            self.func(world)
            self.lock.release()
            sleep(self.interval)

        world = None
        pythoncom.CoUninitialize()


    def stop(self):
        self.keep_alive = False

    def setInterval(self, interval):
        self.lock.acquire()
        self.interval = interval
        self.lock.release()


You are interested primarily in Ticker.start() and Ticker.run() Basically, you need to marshal the world object into the new thread, after which it is safe to be used from there. If, however, you try to use an "unmarshalled" world object from a separate thread, it's almost guaranteed to cause a crash.
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


5,572 views.

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]


Written by Nick Gammon - 5K   profile for Nick Gammon on Stack Exchange, a network of free, community-driven Q&A sites   Marriage equality

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( https://gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Hosted at FutureQuest]