Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Eclipse EMF Model Transaction Development Guide
Previous Page Home Next Page

Sharing Transactions with Other Threads

Transactions are owned by threads. The initial owner of a transaction is the thread in which context it was created. For the duration of a transaction, the owner thread has exclusive access to the contents of the editing domain's resource set, except as described below. The EMF Transaction API provides two mechanisms for multiple threads to cooperatively share access to the resource set: yielding and privileged runnables. Both of these mechanisms do, however, maintain the single-threaded model of EMF by ensuring that only one thread at a time is ever reading or writing.

Yielding Read-only Transactions

Some read-only operations are typically long-running, such as validation (perhaps using the EMF Validation Framework) or searching (perhaps using the EMF Model Query framework). For these kinds of operations, Eclipse provides such facilities as the Jobs API and progress monitors to do work in the background and/or keep the user abreast of what is happening.

Because transactions in a TransactionalEditingDomain lock the resource set for exclusive access by a single thread, a read-only transaction that runs for a long time can severely impair the responsiveness of an application's UI if refreshes require reading the EMF data.

To address these situations, the TransactionalEditingDomain provides a yield() method that suspends the current transaction to allow the next thread waiting for a read-only transaction to start, if there is any such thread waiting. Only read-only transactions may be yielded in this way, because yielding any transaction to a writer would result in the data that a reader has already read being changed, so that when the reader resumes later, its assumptions about the data are invalid. This phenomenon is known as a "dirty read."

final TransactionalEditingDomain domain;
final IProgressMonitor monitor;

// acquire read transaction on this thread
domain.runExclusive(new Runnable() {
    public void run() {
        while (moreToRead()) {
            // ... do a bunch of reading ...
            readSomeStuff();

            // checking the progress monitor is a good opportunity to
            //    yield to other readers
            if (monitor.isCancelled()) {
                forgetIt();
                break;
            }
            
            domain.yield(); // just returns if no readers waiting 
        }
    }});

Read access may be yielded to a thread that is waiting to start a read-only transaction or to a thread that has a read action in progress that is currently suspended on a yield, waiting to resume it. Yielding proceeds in round-robin fashion amongst the set of threads currently waiting for or suspending read-only transactions; there is no facility for prioritization of threads. Any thread wishing to start a read/write transaction must wait until all active read-only transactions have completed.

A practical rule of thumb for deciding when to yield a read transaction is to do it whenever checking a progress monitor for cancellation and/or updating the progress.

Sharing Read/Write Transactions

We have seen how multiple threads with read-only transactions can take turns reading by cooperatively yielding (suspending) their transactions. It is, however, common in Eclipse for a thread to be required to synchronously communicate with another thread in order to accomplish some task.

Probably the most common occurrence of this is in the updating of UI widgets from background threads or jobs. The SWT API requires that all modifications to widgets be performed on a thread designated as the Display thread. What does a thread do if it has a read/write transaction in progress and it needs to execute code on the UI thread in a Display.syncExec() call, and this synchronous runnable might need to read the resource set or even modify it?

The thread that owns a transaction can use the TransactionalEditingDomain.createPrivilegedRunnable(Runnable) method to wrap an operation (encapsulated in a Runnable) in a privileged runnable. This privileged runnable, when executed on some other thread, borrows the original owning thread's transaction for the duration of its execution, which it delegates to the wrapped runnable. This is ideal for use with APIs such as Display.syncExec(), in which the thread that lends its transaction (via the privileged runnable) to the display thread waits for the display thread to finish executing the runnable before resuming.

Privileged runnables can only be used with synchronous inter-thread communication mechanisms such as Display.syncExec(). Attempting asynchronous runnables (as with Display.asyncExec()) will certainly lead to an illegal transaction state. A thread that posts an asynchronous invocation of a privileged runnable will proceed with reading and modifying the resource set, only to find suddenly that it no longers owns the transaction because the other thread has taken it over.

TransactionalEditingDomain domain;
final org.eclipse.swt.widgets.List bookList;

// acquire read transaction on this thread
domain.runExclusive(new Runnable() {
    public void run() {
        // hand it off to the UI thread to read the library and update
        //    the list widget
        Display.syncExec(domain.createPrivilegedRunnable(
            new Runnable() {
                public void run() {
                    // the UI thread now has the transaction to read the resource set
                    List<String> bookTitles = new ArrayList<String>();            
                    for (Book book : library.getBooks) {
                        bookTitles.add(book.getTitle());
                    }
                    
                    // update the UI
                    bookList.setItems(bookTitles.toArray(new String[bookTitle.size()]));
                }   // the UI thread gives up the transaction
            }));

Of course, a real application probably would not directly nest runnables in this way. The code that interacts with the UI thread would more likely be indirectly invoked by a runExclusive() runnable through some possibly deep call stack.

This mechanism works with both read-only and read/write transactions because only a single transaction is involved. The privileged runnable differs from yield in being directed at a specific other thread, which then returns the transaction directly back to the original owner. We do not have multiple independent threads creating transactions for their own purposes, but rather a thread that deliberately continues a synchronous operation on another thread during some interval.

Note that a thread executing a privileged runnable can, in turn, lend the transaction to yet another thread via another privileged runnable. This can be repeated an arbitrary number of times, even cycling back to a thread that is already lending the transaction away in a privileged runnable.


Copyright (c) 2006, 2007 IBM Corporation and others. All Rights Reserved.


 
 
  Published under the terms of the Eclipse Public License Version 1.0 ("EPL") Design by Interspire