Analysis/Multi-Threading

From Apache OpenOffice Wiki
Revision as of 12:57, 21 April 2006 by Kr (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Type: analysis
Status: final
Version: 1.2

Author: Kai Sommerfeld, Kay Ramme

The State of OpenOffice.org Multi Threading

More or less frequently people complain about OOo in respect to multi threading. Either because it is complicated to implement a service, or that there is only few documentation, or that the UNO API is not thread safe, or that it does not scale etc. Unfortunately it is somehow difficult to name the issues in an orthogonal and complete way. Below you find what we identified to be the (most) pressing ones.

Terms

Thread
An activity in a process.
Lock
A synchronization primitive, such as a pthread MutEx
Thread Aware
Code which cares about the threads using it.
Thread Affine
Code which offers services to particular threads only (e.g. on Win32 the DestroyWindow function may only be called with a hWnd created by the same thread). Thread affine code is thread aware.
Thread Safe
Code which can be executed by multiple threads simultaneously, e.g. By protecting access to data. Thread safe code is thread aware.
Thread Transparent
Code which does not show any thread awareness.

General

Issue
OOo does not scale with multiple clients (client threads).
Expectation
OOo scales with multiple clients e.g. calling on multiple documents.
Issue
OOo does not scale on multiple CPUs.
Expectation
OOo leverages multiple CPUs for executing simultaneous tasks, e.g. printing / loading / saving.
Issue
OOo sometimes hangs, waiting for a particular operation to finish.
Expectation
OOo is always alive and reacts immediately on available commands. At least the “abort” command needs to be available always.
Issue
OOo sometimes crashes, when used in ISV scenarios.
Expectation
OOo can be used by multiple ISV (integration) solutions simultaneously.


Programmability / UNO

Issue
There is few to none documentation about the threading model (how can threads be used).
Expectation
There is a well specified threading model.
Issue
There is few to none documentation about the threading architecture (where are threads used to do what and which parts are thread aware to what extend).
Expectation
There is a well specified threading architecture, documenting where threads are used and what does that mean for the programmer.
Issue
Many OOo UNO API implementations are not thread safe.
Expectation
The OOo UNO API implementations can be used by multiple threads and clients simultaneously
Sample Code
See appendix – Threaded Office Crasher
Note
Theoretically that means, that the OOo UNO API can not reliable be programmed in languages utilizing dedicated threads for finalization (e.g. CLI, Java), so in practise we do not know of any real problem ever shown up
Issue
There is no proof that the OOo UNO API is thread safe.
Expectation
There is a specified threading architecture ensuring, that the OOo UNO API is thread safe
Comment
Testing is not sufficiently and realistically possible.
Issue
Per definition, every UNO component must be implemented thread safe.
Expectation
It can be decided case by case, what the threading architecture of a particular component is.
Issue
Per definition, every UNO component must release all locks before calling another object.
Expectation
A thread safe component can hold locks, while calling other objects.
Comment
It is not programmable to release all locks while calling out.
Issue
It is hard to implement OLE client components.
Expectation
OLE client code can be implemented easily as UNO components.
Issue
Win32 - OSL threads are always MTA threads.
Reference
sal/osl/W32/thread.c:103 - CoInitializeEx(COINIT_MULTITHREADED)
Expectation
OSL threads are threading model neutral (can be used for any kind of COM / OLE programming (STA / MTA)).
Issue
There are two competing threading models / architectures in place (UNO, VCL).
Expectation
There is one well specified threading model / architecture.

VCL

Issue
The VCL threading behavior is not platform transparent, it behaves differently on Win32 compared to UNIX.
Expectation
VCL can be programmed in the same way on any platform.
Example
On Win32 destroying a window needs to be delegated into the “creator” thread.
Issue
Win32 – The VCL API is partly thread affine.
Expectation
No OOo API is thread affine in any kind (depends on threading architecture).
Issue
Provides the "Solar MutEx", which needs to be locked before every VCL operation.
Expectation
VCL is thread transparent (depends on threading architecture).
Comment
This is error prone and introduces overhead.
Issue
VCL releases the "Solar MutEx" when entering the main loop, even if VCL code is on the stack.
Expectation
VCL is thread transparent (depends on threading architecture).
Comment
This is not viable.
Sample Code
See appendix – D&D Office Crasher
Issue
Win32 – The VCL initializing thread gets initialized as a STA thread.
Reference
vcl/win/source/app/salinst.cxx:233 - CoInitialize
Expectation
VCL is threading model neutral.

Office Code

Issue
Win32 – Initializing code partly relies on the same thread to enter the main loop (e.g. DDE).
Expectation
Systems can be initialized by any thread (depends on threading architecture).
Issue
Code tricks VCLs thread affinity by posting messages into the main thread.
Expectation
Code does not workaround threading weaknesses.
Example
To destroy windows in the “main” thread.
Issue
There is thread related dead or unproven code.
Expectation
Thread aware code is well tested.

Performance

Issue 
Runtime performance is impacted by many locks becoming con-/de-structed and acquired/released.
Expectation 
Locks are only used in scaling sensitive components.
Reference 
See Appendix / Numbers
Issue
Runtime performance is impacted by the need to use interlock counters for reference counting.
Reference
See Appendix / Numbers
Expectation
Interlock counters are only used in scaling sensitive components.
Issue
Increased code size because of needed thread synchronizations.
Reference
See Appendix / Numbers
Expectation
Thread aware code is only used in scaling sensitive parts.

Development Costs

Issue: Increased development time because of implementing (not really :-) thread safe code.
Issue: Increased development time because of implementing fine grained synchronization.
Issue: Increased maintenance costs due to problems with bugs in thread safe implementations.
Expectation: Development most focusses on behavior / performance and less on not usable scalability.

Summary

The current state of OOo threading is unsatisfying in multiple dimensions and areas and urgently needs to be taken care of and cleaned up.


Appendix

Acronyms

VCL
Visual Components Library - OOos GUI abstraction layer.
UNO
Universal Network Objects - OOos component model.
Win32
MS Windows API.
COM
Component Object Model - MS component technology.
OLE
MS technology for compound documents and such. OLE is based on COM.
OSL
Operating System Layer – UNOs platform abstraction for basic operating system tasks, e.g. as file creation, socket communication or process creation.
MTA
Multi Threaded Apartment – An object space which can be populated by multi threads.
STA
Single Threaded Apartment – An object space which is populated by exactly one thread.

Numbers

The following table gives the call numbers for MutExes and interlock counters for a simple scenario. The scenario looks like this:

  • Start the office (soffice.bin).
  • Open an empty Writer document via the menu.
  • Terminate the office via the menu.

{- | Function | Calls |- | osl_acquireMutex || 482419 |- | osl_releaseMutex || 483692 |- | osl_tryToAcquireMutex || 1257 |- | osl_createMutex || 7427 |- | osl_destroyMutex || 6886 |- | osl_incrementInterlockedCount || 1982252 |- | osl_decrementInterlockedCount || 1960064 |}

Threaded Office Crasher

The following patch changes the “TextDocuments” example (“<SDK>/examples/DevelopersGuide/Text/TextDocuments.java“, tested with SRC680m124) of the OOo SDK. After applying, two independent threads start to alter the same document. The office typically only survives this some ten seconds, finally dying with varying stacks.

--- examples/DevelopersGuide/Text/TextDocuments.java        2005-01-31 18:03:49.000000000 +0100
+++ TextDocuments.java        2005-11-08 16:26:11.000000000 +0100
@@ -38,6 +38,20 @@ 
  *     
  *************************************************************************/
 
+/******************************************************************* 
+ *** BBBBB   EEEEEE       A     W         W    A     RRRRR   EEEEEE
+ *** B    B  E           A A    W         W   A A    R    R  E
+ *** B    B  E          A   A   W    W    W  A   A   R    R  E
+ *** BBBBB   EEEE       A   A    W  W W  W   A   A   RRRRR   EEEE
+ *** B    B  E          AAAAA    W W   W W   AAAAA   R  R    E
+ *** B    B  E         A     A   W W   W W  A     A  R   R   E
+ *** BBBBB   EEEEEE    A     A    W     W   A     A  R    R  EEEEEE
+ *** 
+ *** - THIS KILLS THE RUNNING OPENOFFICE 
+ *** - THIS MAY MAKE YOU DESKTOP QUITE SLOW TO RESPONSE 
+ *** 
+ *******************************************************************/ 
+ 
 import com.sun.star.awt.Point;
 import com.sun.star.awt.Size;
 import com.sun.star.awt.FontWeight;
@@ -145,7 +159,7 @@ import java.util.Hashtable; 
  *
  * @author  Martin Gallwey, Dietrich Schulten
  */
-public class TextDocuments { 
+public class TextDocuments implements Runnable { 
     // adjust these constant to your local printer!
     private static String sOutputDir;
 
@@ -162,36 +176,45 @@ public class TextDocuments { 
     private XTextContent mxFishSection = null;
     private Random maRandom = null;
     
+        XComponent mxEmptyWriterComponent;
+ 
     /** Creates a new instance of TextDocuments */
     public TextDocuments() {
     }
     
+ 
+        public void run() {
+                while(true) {
+                        try {
+                                runDemo();
+                        }
+                        catch (java.lang.Exception e){
+                        }
+                }
+        }
+ 
     /**
      * @param args the command line arguments
      */
-    public static void main(String[] args) {
-    TextDocuments textDocuments1 = new TextDocuments();
-    try {
-            // output directory for store test;
-            sOutputDir = args[0];
-            
-            textDocuments1.runDemo();
-        }
-        catch (java.lang.Exception e){
-            System.out.println(e.getMessage());
-            e.printStackTrace();
-        }
-        finally {
-            System.exit(0);
-        }
+    public static void main(String[] args) throws Exception {
+                TextDocuments textDocuments1 = new TextDocuments();
+                // create empty swriter document
+                textDocuments1.mxEmptyWriterComponent = textDocuments1.newDocComponent("swriter");
+ 
+                for (int i = 0; i < 2; ++ i) {
+                        System.out.println( "#################### Thread #" + i);
+ 
+                        new Thread(textDocuments1).start();
+                }
     }
     
     protected void runDemo() throws java.lang.Exception {
-            storePrintExample(); // depends on printer name
-            templateExample();   
-            viewCursorExample(); // makes changes to the current document,
-                                 // use with care
-            editingExample();
+//             storePrintExample(); // depends on printer name
+//             templateExample();   
+//             viewCursorExample(); // makes changes to the current document,
+//                                  // use with care
+ 
+                editingExample();
     }
     
     /** Sample for use of templates
@@ -327,11 +350,9 @@ public class TextDocuments { 
      * developer's manual
      */
     private void editingExample () throws java.lang.Exception {
-        // create empty swriter document
-        XComponent xEmptyWriterComponent = newDocComponent("swriter");
         // query its XTextDocument interface to get the text
         mxDoc = (XTextDocument)UnoRuntime.queryInterface(
-            XTextDocument.class, xEmptyWriterComponent);
+            XTextDocument.class, mxEmptyWriterComponent);
         
         // get a reference to the body text of the document
         mxDocText = mxDoc.getText();

D&D Office Crasher

The following patch changes the “TextDocuments” example (“<SDK>/examples/DevelopersGuide/Text/TextDocuments.java“, tested with SRC680m124) of the OOo SDK.

To test, start the “TextDocuments” example by typing

       make TextDocuments.run

After the Writer window opens, you have ten seconds to type some text (e.g. “dt”<F3>), to select it and to start dragging it. Just keep the drag, the client will try to close the current document and the office dies. This is because of the Solar MutEx getting released by VCL during the yield operation.

*** /so/ws/SRC680/src.m136/odk/examples/DevelopersGuide/Text/TextDocuments.java        2005-01-31 18:03:49.000000000 0100
--- /local/kr/TextDocuments.java        2005-11-22 13:58:59.000000000 +0100
*************** 
*** 38,43 **** 
--- 38,56 ---- 
   *     
   *************************************************************************/
  
+ /******************************************************************* 
+  *** BBBBB   EEEEEE       A     W         W    A     RRRRR   EEEEEE
+  *** B    B  E           A A    W         W   A A    R    R  E
+  *** B    B  E          A   A   W    W    W  A   A   R    R  E
+  *** BBBBB   EEEE       A   A    W  W W  W   A   A   RRRRR   EEEE
+  *** B    B  E          AAAAA    W W   W W   AAAAA   R  R    E
+  *** B    B  E         A     A   W W   W W  A     A  R   R   E
+  *** BBBBB   EEEEEE    A     A    W     W   A     A  R    R  EEEEEE
+  ***
+  *** - THIS KILLS THE RUNNING OPENOFFICE
+  ***
+  *******************************************************************/
+  
  import com.sun.star.awt.Point;
  import com.sun.star.awt.Size;
  import com.sun.star.awt.FontWeight;
*************** public class TextDocuments { 
*** 166,171 **** 
--- 179,194 ---- 
      public TextDocuments() {
      }
      
+     private void openClose_writerDocument() throws Exception {
+         Object desktop = getRemoteServiceManager().createInstanceWithContext("com.sun.star.frame.Desktop", mxRemoteContext);
+         XComponentLoader xComponentLoader   = (XComponentLoader)UnoRuntime.queryInterface(XComponentLoader.class, desktop);
+  
+         XComponent xComponent = xComponentLoader.loadComponentFromURL("private:factory/swriter", "_blank", 0, new PropertyValue[0]);
+  
+                  Thread.sleep(10000);
+                  xComponent.dispose();
+     }
+  
      /**
       * @param args the command line arguments
       */
*************** public class TextDocuments { 
*** 173,181 **** 
      TextDocuments textDocuments1 = new TextDocuments();
      try {
              // output directory for store test;
!             sOutputDir = args[0];
              
!             textDocuments1.runDemo();
          }
          catch (java.lang.Exception e){
              System.out.println(e.getMessage());
--- 196,205 ---- 
      TextDocuments textDocuments1 = new TextDocuments();
      try {
              // output directory for store test;
! //             sOutputDir = args[0];
              
! //             textDocuments1.runDemo();
!                         textDocuments1.openClose_writerDocument();
          }
          catch (java.lang.Exception e){
              System.out.println(e.getMessage());
Personal tools