[previous] [up] [next]     [contents] [index]
Next: Callbacks for Blocked Threads Up: Threads Previous: Threads

Threads in Embedded MzScheme with Event Loops

When MzScheme is embedded in an application with an event-based model -- i.e., the execution of Scheme code in the main thread is repeatedly triggered by external events until the application exits -- special hooks must be set to ensure that non-main threads execute correctly. For example, during the execution in the main thread, a new thread may be created; the new thread may still be running when the main thread returns to the event loop, and it may be arbitrarily long before the main thread continues from the event loop. Under such circumstances, the embedding program must explicitly allow MzScheme to execute the non-main threads; this can be done by periodically calling the function scheme_check_threads.

Thread-checking only needs to be performed when non-main threads exist (or when there are active callback triggers). The embedding application can set the global function pointer scheme_notify_multithread to a function that takes an integer parameter and returns void. This function is be called with 1 when thread-checking becomes necessary, and then with 0 when thread checking is no longer necessary. An embedding program can use this information to prevent unnecessary scheme_check_threads polling.

The below code illustrates how MrEd formerly set up scheme_check_threads polling using the wxWindows wxTimer class. (Any regular event-loop-based callback is appropriate.) The scheme_notify_multithread pointer is set to MrEdInstallThreadTimer. (MrEd no longer work this way, however.)

class MrEdThreadTimer : public wxTimer
{
 public:
  void Notify(void); /* callback when timer expires */
};

static int threads_go;
static MrEdThreadTimer *theThreadTimer;
#define THREAD_WAIT_TIME 40

void MrEdThreadTimer::Notify()
{
  if (threads_go)
    Start(THREAD_WAIT_TIME, TRUE);

  scheme_check_threads();
}

static void MrEdInstallThreadTimer(int on)
{
  if (!theThreadTimer)
    theThreadTimer = new MrEdThreadTimer;

  if (on)
    theThreadTimer->Start(THREAD_WAIT_TIME, TRUE);
  else
    theThreadTimer->Stop();

  threads_go = on;
  if (on)
    do_this_time = 1;
}

An alternate architecture, which MrEd now uses, is to send the main thread into a loop, which blocks until an event is ready to handle. MzScheme automatically takes care of running all threads, and it does so efficiently because the main thread blocks on a file descriptor, as explained in section 3.7.3.





PLT