User:Kr/Holder

From Apache OpenOffice Wiki
< User:Kr
Revision as of 14:27, 2 August 2006 by Kr (Talk | contribs)

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

this page holds various text fragments:

, or


Thread-Free

Thread-free objects may be used in any threading environment. While doing so, they certainly need to respect particular environment related constraints. An implementation being able to deal with one of thread-unsafe, thread-safe or thread-affine objects only, is thread-specialized on this particular threading model, while a thread-free implementation is able to deal with any threading model. In essence, a thread-free object appears thread agnostic to the outside (i.e. can be utilized in any of the three environment types, without the cost of environment entry/exit), but needs in fact to distinguish between the client environments internally.

Note: The Uno runtime provides APIs for implementing any whished scenario. Including objects shared between different purpose environments or the instantiation of a thread-safe component in a thread-unsafe environment. These mechanisms are in place to implement the threading framework itself, and to allow the programmer to gain full control, if needed.


Capabilities

Code may actually vary in its capabilities regarding 'transparent concurrency'. Code may be differentiated into code using

  • global variables, or
  • thread local variables, or
  • parameters only ("pure"), or
  • value parameters only, or
  • doing internal protection of critical sections, or
  • not doing internal protection.

Such categorizations help to decide, what one can do with a particular implemention. Also the codes threading type is a compile time information and may therefor be used during compilation, so that the compiler may give errors when mixing thread-safe and thread-unsafe code in a multi-thread scenario.



Components

Components do provide their implementation environment. If a component should be implemented thread-unsafe, this needs to be reflected in the target environment.

C++

Components directly provide their environments. Which basically is the ABI plus any thread related specialisation (":unsafe" or ":affine"). The implementation of the component_getImplementationEnvironment function for a thread-unsafe component needs to reflect this unsafeness, e.g:

extern "C" void SAL_CALL component_getImplementationEnvironment(sal_Char        const ** ppEnvTypeName, 
								uno_Environment       ** ppEnv)
{
	*ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME ":unsafe";
}

A component implementing thread-safe and thread-transparent objects may want to utilize these capabilities by avoiding any mapping, this can be done by implementing the component_getImplementationEnvironmentExt function, e.g.:

extern "C" void SAL_CALL component_getImplementationEnvironmentExt(sal_Char        const ** ppEnvTypeName, 
	                                                           uno_Environment       ** ppEnv,
	                                                           sal_Char        const  * pImplName,
                                                                   uno_Environment        * pSrcEnv
)
{
  rtl::OUString envName(RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING));
  envName += cppu::EnvDcp_getPurpose(Environment(pSrcEnv).getTypeName();

  uno_getEnvironment(ppEnv, envName.pData, NULL);
}

Implementing this function, the component may very well select the threading respectively target environments depending on the provided implementation names.

Uno Libraries

Uno libraries may implement objects as well as components or applications. These objects may be

Libraries can not rely on the runtime to handle thread (respectively purpose) related mapping. Libraries need to care of thread related environments by their own. As well as components or applications, libraries may be implemented thread-specialized or thread-free. Depending on the capabilities of the particular programming language and language binding, correct specialization may be ensured during compilation time, e.g. by dedicated reference types.

C++

The current C++ UNO language binding only supports free (cppu::FreeReference) and classic (com::sun::star::uno::Reference) references. The API of thread-free libraries should reflect the "freeness" by using the cppu::FreeReference in its definition, e.g.:

// Declaration
cppu::FreeReference<XSingleServiceFactory> get_a_factory(void);

For compatibility reasons, classic UNO references (com::sun::star::uno::Reference) may be used, doing a runtime check for the thread type of the passed or requested objects, e.g.:

static void creator(va_list param) {
	cppu::FreeReference * prFactory = va_arg(param, cppu::FreeReference<XSingleServiceFactory> *);

    rFactory->set(new MyThreadUnsafeFactory());
}

// API Implementation
uno::Reference<XSingleServiceFactory> get_a_factory(void)
{
  cppu::FreeReference<XSingleServiceFactory> rFactory(new MyThreadUnsafeFactory());

  uno::Environment(rtl::OUString(RTL_CONSTASCII_PARAM("uno:unsafe"))).invoke(creator, &rFactory);

  return rFactory;
}

The cppuhelper library dynamically checks the current environment, and returns matching references, e.g. guaranteeing that thread-safe and thread-unsafe objects do not get mixed.

Applications

Applications are basically like libraries, except that no Uno objects are passed in, or are returned. Application code implemented other than in the thread-safe environment needs to explicitly enter the wished purpose environment respectively thread related environment before calling any particular Uno aware thread specialized library. Uno aware libraries may than provide matching objects, depending on their threading architecture. By default, applications start in the thread-safe environment.

C++

An application implementing thread-unsafe objects to be passed to some Uno components may look like this:

class MyThreadUnsafeObject : ... {
  ...
};

SAL_IMPLEMENT_MAIN()
{
  cppu::EnvGuard unsafeGuard(Environment(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("uno:unsafe"))));

  // Get a thread unsafe component context.
  Reference< XComponentContext> xCtxt(cppu::defaultBootstrap_InitialComponentContext());
  ...
  xObject.set(new MyThreadUnsafeObject());
  ...
  return 0;
}

Note: The planned introduction of implementation environments is going to be usable by the application programmer as well. It basically removes the necessity to explicitly enter a particular purpose environment.

Using Threads

You may create threads in your implementation. Depending on the selected threading architecture, these threads may are allowed to be visible from the outside or not. If your implementation is to be instantiated in a

Obviously, invisible threads can be used and created anytime anyway. Invisible threads do not harm thread-transparency by definition.

Unsafe / Affine Code

If you are writing thread-unsafe or thread-affine code, any created thread to run outside the current (thread-unsafe / -affine) environment. The objects, which should be used by this thread, need to be mapped to the threads environment, which typically will be the thread-safe environment.

Mapped objects need to be managed by the belonging enviroment only, as long as this environment has not been entered explicity, otherwise methods (e.g. release or acquire) of the objects may be called from the wrong environment.

C++

Do not enter the environment explicity, but only implicity when calling methods on mapped objects (assuming the objects have been implemented in the target environment).

Use the shield helper:

class MyThread : public Thread 
{
  uno::Reference<XInterface> m_xInterface;

public:
  MyThread(uno::Reference<XInterface> const & xInterface)
    : m_xInterface(uno::shield(xInterface), SAL_NO_ACQUIRE)
  {
  }
};

Do the mapping by hand:

class MyThread : public Thread 
{
  uno::Reference<XInterface> m_xInterface;

public:
  MyThread(uno::Reference<XInterface> const & xInterface);
};

MyThread::MyThread(uno::Reference<XInterface> const & xInterface)
{
  uno::Mapping unsafe2safe(uno::getCurrentEnvironment(), 
                           rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(CPPU_STRINGIFY(CPPU_ENV))));
		
  m_xInterface.set(unsafe2safe.mapInterface(pT, getCppuType(m_xInterface)), 
		   SAL_NO_ACQUIRE);
}

Just enter the environment add do all calls while being in it. Obviously, releasing the objects also needs to be done in the environment.

class MyThread : public Thread 
{
  uno::Environment           m_refEnv;
  uno::Reference<XInterface> m_xInterface;

  void i_doSomething();

public:
  MyThread(uno::Reference<XInterface> const & xInterface);

  void doSomething();
};

MyThread::MyThread(uno::Reference<XInterface> const & xInterface)
 : m_xInterface(xInterface), m_refEnv(uno::getCurrentEnvironment());
{
}

void MyThread::doSomething()
{
  // do not do any slow/blocking operations here, as the target environment is
  // currently entered, and no other thread may enter at the moment...
  m_xInterface->...
}

static void s_doSomething(va_list param)
{
  MyThread * pMyThread = va_arg(param, MyThread *);
  pMyThread->i_doSomething();
}

void MyThread::doSomething()
{
  m_refEnv.invoke(s_doSomething, this);
}

MyThread::~MyThread() 
{
  m_refEnv.invoke(clearRefs);
}

These may be eased by using the FreeReference.

Free References

For some language bindings, there is support for shareable or free references (optional, e.g. Uno/Cpp/Spec/FreeReference). These free references may be used in any particular purpose environment, as they are taking care of the appropriate mapping of any objects prior to the invokation of a particular method.

C++
class MyUnoObject;

class MyObject 
{
  cppu::FreeReference<uno::XInterface> m_obj;

public:
  MyObject(XInterface * xInterface)
    : m_obj(xInterface, SAL_NO_ACQUIRE)
  {}

  void doSomething() 
  {
    m_obj.aMethod();
  }
};

class MyThread : public Thread 
{
  MyObject * m_pMyObject;
public:
  MyThread(MyObject * pMyObject);

  void run() 
  {
    m_pMyObject->doSomething();
  }
};

...
MyObject * pMyObject = new MyObject(new UnoObject());
MyThread * pMyThread = new pMyThread(pMyObject);

pMyObject->doSomething();
...








Uno Components

Components actively provide their implementation environment. If a particular object adheres to a particular environment (e.g. "jni:unsafe"), then this needs to be reflected in the target environment only.

Uno Libraries

Uno libraries can not rely on the runtime to handle environment related mapping of objects automatically, as the caller and the callee are linked directly, without any component loader or similar in between. Therefor Uno libraries need to care for environments by their own.

Uno libraries may be implemented environment-free, actually always providing matching objects.

Uno Applications

Applications are basically like libraries, except that no Uno objects are passed in, or are returned. Application code implemented other than in the thread-safe environment needs to explicitly enter the wished (purpose) environment before calling any particular environment-specialized Uno library.

Note: The planned introduction of implementation environments is going to be usable by the application programmer as well. It basically removes the necessity to explicitly enter a particular purpose environment.

Personal tools