blob: cb593372af6368d2334297c2254cae04461aa07a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DECAF_LANG_THREADLOCAL_H_
#define _DECAF_LANG_THREADLOCAL_H_
#include <decaf/util/Config.h>
#include <decaf/internal/util/concurrent/ThreadLocalImpl.h>
namespace decaf {
namespace lang {
/**
* This class provides thread-local variables. These variables differ from their normal
* counterparts in that each thread that accesses one (via its get or set method) has its
* own, independently initialized copy of the variable. ThreadLocal instances are typically
* private static fields in classes that wish to associate state with a thread (e.g., a
* user ID or Transaction ID). This class imposes the restriction on the type that it will
* contains that it must by both assignable and copyable.
*
* Each thread holds an implicit reference to its copy of a thread-local variable as long as
* the thread is alive and the ThreadLocal instance is accessible; after a thread goes away,
* all of its copies of thread-local instances are destroyed.
*
* @since 1.0
*/
template <typename E>
class ThreadLocal : protected decaf::internal::util::concurrent::ThreadLocalImpl {
private:
ThreadLocal(const ThreadLocal&);
ThreadLocal& operator= (const ThreadLocal&);
public:
/**
* Creates a new instance of a ThreadLocal
*/
ThreadLocal() : ThreadLocalImpl() {}
virtual ~ThreadLocal() {
try {
removeAll();
} catch(...) {}
}
/**
* Returns the value in the current thread's copy of this thread-local variable. If the
* variable has no value for the current thread, it is first initialized to the value
* returned by an invocation of the initialValue() method.
*
* @return the current thread's value for this thread local.
*/
E& get() {
void* bytes = getRawValue();
if (bytes == NULL) {
E* value = new E();
*value = initialValue();
setRawValue((void*)value);
bytes = value;
}
return *((E*)bytes);
}
/**
* Sets the current thread's copy of this thread-local variable to the specified value.
* Most subclasses will have no need to override this method, relying solely on the
* initialValue() method to set the values of thread-locals.
*
* @param value
* The new value to assign to this Thread local.
*/
void set(const E& value) {
setRawValue((void*)(new E(value)));
}
/**
* Removes the current thread's value for this thread-local variable. If this thread-local
* variable is subsequently read by the current thread, its value will be reinitialized by
* invoking its initialValue() method, unless its value is set by the current thread in the
* interim. This may result in multiple invocations of the initialValue method in the
* current thread.
*/
void remove() {
this->setRawValue(NULL);
}
protected:
/**
* Returns the current thread's "initial value" for this thread-local variable. This
* method will be invoked the first time a thread accesses the variable with the get()
* method, unless the thread previously invoked the set() method, in which case the
* initialValue method will not be invoked for the thread. Normally, this method is
* invoked at most once per thread, but it may be invoked again in case of subsequent
* invocations of remove() followed by get().
*
* This implementation simply returns E(); if the programmer desires thread-local
* variables to have an initial value other than E(), ThreadLocal must be subclassed,
* and this method overridden. Typically, an inner class will be used.
*
* @param value
* Pointer to the thread local value created by this thread when get() is first called.
*/
virtual E initialValue() const {
return E();
}
protected:
virtual void doDelete(void* value) {
if (value != 0) {
delete static_cast<E*>(value);
}
}
};
}}
#endif /* _DECAF_LANG_THREADLOCAL_H_ */