ICU-2787 add u_init() to work around thread safety problems with existing lazy init

X-SVN-Rev: 11735
This commit is contained in:
Andy Heninger 2003-04-30 00:09:18 +00:00
parent 7672ca8952
commit 702ddea7c2
3 changed files with 86 additions and 4 deletions

View File

@ -15,6 +15,7 @@
*/
#include "unicode/uclean.h"
#include "unicode/uchar.h"
#include "ucln_cmn.h"
#include "umutex.h"
#include "ucln.h"
@ -82,3 +83,46 @@ u_cleanup(void)
umtx_destroy(NULL);
}
static UMTX InitMutex = NULL;
U_CAPI void U_EXPORT2
u_init(UErrorCode *status) {
/*
* Lock and unlock the global mutex, thus forcing into existence
* if it hasn't already been created.
*/
umtx_lock(NULL);
umtx_unlock(NULL);
/* Lock a private mutex for the duration of the initialization,
* ensuring that there are no races through here, and to serve as
* a memory barrier. Don't use the global mutex, because of the
* possibility that some of the functions called within here might
* use it.
*/
umtx_lock(&InitMutex);
/*
* Do a simple operation using each of the data-requiring APIs that do
* not have a service object, ensuring that the required data is loaded.
*/
/* Char Properties */
u_hasBinaryProperty(0x20, UCHAR_WHITE_SPACE);
/* Char Names */
{
char buf[100];
u_charName(0x20, U_UNICODE_CHAR_NAME, buf, 100, status);
}
/* TODO: the rest of 'em */
umtx_unlock(&InitMutex);
}

View File

@ -19,6 +19,31 @@
#include "unicode/utypes.h"
/**
* Initialize ICU. This function loads and initializes data items
* that are required internally by various ICU functions. Use of this explicit
* initialization is required in multi-threaded applications; in
* single threaded apps, use is optional, but incurs little additional
* cost, and is thus recommended.
* <p>
* In multi-threaded applications, u_init() should be called in the
* main thread before starting additional threads, or, alternatively
* it can be called in each individual thread once, before other ICU
* functions are called in that thread. In this second scenario, the
* application must guarantee that the first call to u_init() happen
* without contention, in a single thread only.
* <p>
* Extra, repeated, or otherwise unneeded calls to u_init() do no harm,
* other taking a small amount of time.
*
* @param pErrorCode An ICU UErrorCode parameter. It must not be <code>NULL</code>.
* An Error will be retuned if some required part of ICU data can not
* be loaded or initialized.
*
*/
U_CAPI void U_EXPORT2
u_init(UErrorCode *status);
/**
* Clean up the system resources, such as allocated memory or open files,
* used in all ICU libraries. This will free/delete all memory owned by the
@ -39,10 +64,10 @@
* results.
* <p>
* After calling u_cleanup(), an application may continue to use ICU by
* creating an ICU C++ object or opening new items (converters, collators,
* etc.) and using them. An application must use ICU from one single
* thread before allowing other threads or processes from using ICU. This
* is so that the ICU libraries can reinitialize in a thread safe manner.
* calling u_init(). An application must invoke u_init() first from one single
* thread before allowing other threads call u_init(). All threads existing
* at the time of the first thread's call to u_init() must also call
* u_init() themselves before continuing with other ICU operations.
* <p>
* The use of u_cleanup() just before an application terminates is optional,
* but it should be called only once for performance reasons. The primary

View File

@ -1064,6 +1064,19 @@ main(int argc, char* argv[])
fprintf(stdout, " Leaks (l) : %s\n", (leaks? "On" : "Off"));
fprintf(stdout, "-----------------------------------------------\n");
// Check that u_init() works
errorCode = U_ZERO_ERROR;
u_init(&errorCode);
if (U_FAILURE(errorCode)) {
fprintf(stdout,
"*** u_init() failed with error code = %s\n"
"*** Check the ICU_DATA environment variable and\n"
"*** check that the data files are present.\n",
u_errorName(errorCode));
return 1;
}
// initial check for the default converter
errorCode = U_ZERO_ERROR;
cnv = ucnv_open(0, &errorCode);