Globalizacja aplikacji i wątki
Natknąłem się na pewne zachowanie
.Net Frameworka, które było zupełnie odmienne od tego, którego się spodziewałem.
Problem dotyczy globalizacji i wątków. Okazuje się, że mając aplikację, która
jest zlokalizowana na wiele języków musimy zwrócić szczególną uwagę za każdym
razem gdy korzystamy z wątków.
Ustawienia dotyczące kultury są
właściwościami wątku. W systemie Windows przy starcie wątku ustawienia kultury pobierane
są z ustawień systemowych. Zatem jeżeli uruchamiamy aplikację, jej watek otrzymuje
ustawienia użytkownika. Działanie to jest jak najbardziej oczekiwane. Okazuje
się jednak, że tworzone w aplikacji kolejne watki otrzymują ustawienia
kulturowe w taki sam sposób jak wątek pierwszy. Może nie było by w tym nic
złego, ale osobiście oczekiwałem zachowania odwrotnego – czyli że nowy wątek
otrzyma takie same ustawienia jak wątek główny. Natomiast gdy w międzyczasie zmienimy
ustawienia kulturowe pierwszego wątku to pojawiają się dodatkowe problemy.
Wyobraźmy sobie aplikację, która
przed uruchomieniem wyświetla okno, w którym możemy wybrać język w jakim
chcemy, żeby się uruchomiła. Wybierając język inny niż ten, który znajduje się
w ustawieniach systemu, będziemy działać swobodnie dopóki nie aplikacja nie
zacznie korzystać z wątków.
Ja, będąc niedoświadczonym
programistą, założyłem, że skoro aplikacja ma określone ustawienia kulturowe w
pierwszym wątku, to tworząc nowe wątki ustawienia te zostaną zachowane
(skopiowane z wątku, który tworzy nowe watki). Okazuje się jednak, że CLR nie
zawiera żadnego mechanizmu kontrolowania ustawień kulturowych wątków tworzonych
w danym procesie. Dlatego każdy tworzony wątek będzie miał ustawienia te
pobrane z systemu Windows.
Dobrze, skoro już wiemy o tych
niuansach, to trzeba się do tego przystosować. Jeżeli ręcznie tworzymy wątki to
nie ma z tym żadnego problemu. Klasa Thread ma odpowiednie właściwości, dzięki
którym możemy ustawienia kulturowe ustawić według własnego uznania. Ja jednak
korzystam zwykle z puli wątków (klasa ThreadPool). Jak się szybko okazało klasa
ta nie ma żadnego bezpośredniego wsparcia dla uruchamiania wątków z innymi
ustawieniami kulturowymi. A szkoda. Skoro reguły są jasne, to powinniśmy chociaż
dostać jakieś przeciążenie metody QueueUserWorkItem pozwalające określić
ustawienia kulturowe uruchamianego wątku. A tak trzeba się tym ręcznie bawić i określać
ustawienia kulturowe już w metodzie, uruchomionej w osobnym wątku, co moim
zdaniem tylko wprowadza niepotrzebne zamieszanie w kodzie. Uważam, że można
było tego uniknąć udostępniając odpowiednie API.
Podsumowując okazuje się, że
pracując z aplikacją, która ma być lokalizowana na inne języki musimy
szczególną uwagę zwrócić na obsługę wątków i odpowiednio ustawiać im
właściwości kulturowe. Niemniej jednak zachowanie to jest dla mnie zgoła nie intuicyjne.
Bo przecież zwykle chcemy, aby cała aplikacja działała z tymi samymi
ustawieniami kulturowymi, a przypadki odwrotne są raczej sporadyczne. A może
jest jakieś dobre uzasadnienie tego stanu rzeczy?