1919# cython: linetrace=True
2020# cython: freethreading_compatible = True
2121
22- """ This module implements several device creation helper functions:
22+ """
23+ This module implements several device creation helper functions:
2324
2425 - wrapper functions to create a SyclDevice from the standard SYCL
2526 device selector classes.
@@ -47,7 +48,7 @@ from ._backend cimport ( # noqa: E211
4748 _device_type,
4849)
4950
50- from contextvars import ContextVar
51+ import threading
5152
5253from ._sycl_device import SyclDeviceCreationError
5354from .enum_types import backend_type
@@ -289,7 +290,8 @@ cpdef int get_num_devices(
289290
290291
291292cpdef cpp_bool has_cpu_devices():
292- """ A helper function to check if there are any SYCL CPU devices available.
293+ """
294+ A helper function to check if there are any SYCL CPU devices available.
293295
294296 Returns:
295297 bool:
@@ -301,7 +303,8 @@ cpdef cpp_bool has_cpu_devices():
301303
302304
303305cpdef cpp_bool has_gpu_devices():
304- """ A helper function to check if there are any SYCL GPU devices available.
306+ """
307+ A helper function to check if there are any SYCL GPU devices available.
305308
306309 Returns:
307310 bool:
@@ -313,7 +316,8 @@ cpdef cpp_bool has_gpu_devices():
313316
314317
315318cpdef cpp_bool has_accelerator_devices():
316- """ A helper function to check if there are any SYCL Accelerator devices
319+ """
320+ A helper function to check if there are any SYCL Accelerator devices
317321 available.
318322
319323 Returns:
@@ -328,7 +332,8 @@ cpdef cpp_bool has_accelerator_devices():
328332
329333
330334cpdef SyclDevice select_accelerator_device():
331- """ A wrapper for ``sycl::device{sycl::accelerator_selector_v}`` constructor.
335+ """
336+ A wrapper for ``sycl::device{sycl::accelerator_selector_v}`` constructor.
332337
333338 Returns:
334339 dpctl.SyclDevice:
@@ -350,7 +355,8 @@ cpdef SyclDevice select_accelerator_device():
350355
351356
352357cpdef SyclDevice select_cpu_device():
353- """ A wrapper for ``sycl::device{sycl::cpu_selector_v}`` constructor.
358+ """
359+ A wrapper for ``sycl::device{sycl::cpu_selector_v}`` constructor.
354360
355361 Returns:
356362 dpctl.SyclDevice:
@@ -372,7 +378,8 @@ cpdef SyclDevice select_cpu_device():
372378
373379
374380cpdef SyclDevice select_default_device():
375- """ A wrapper for ``sycl::device{sycl::default_selector_v}`` constructor.
381+ """
382+ A wrapper for ``sycl::device{sycl::default_selector_v}`` constructor.
376383
377384 Returns:
378385 dpctl.SyclDevice:
@@ -394,7 +401,8 @@ cpdef SyclDevice select_default_device():
394401
395402
396403cpdef SyclDevice select_gpu_device():
397- """ A wrapper for ``sycl::device{sycl::gpu_selector_v}`` constructor.
404+ """
405+ A wrapper for ``sycl::device{sycl::gpu_selector_v}`` constructor.
398406
399407 Returns:
400408 dpctl.SyclDevice:
@@ -417,21 +425,23 @@ cpdef SyclDevice select_gpu_device():
417425
418426cdef class _DefaultDeviceCache:
419427 cdef dict __device_map__
428+ cdef object _cache_lock
420429
421430 def __cinit__ (self ):
422431 self .__device_map__ = {}
423-
424- cdef get_or_create(self ):
425- """ Return instance of SyclDevice and indicator if cache
426- has been modified"""
427- key = 0
428- if key in self .__device_map__:
429- return self .__device_map__[key], False
430- dev = select_default_device()
431- self .__device_map__[key] = dev
432- return dev, True
433-
434- cdef _update_map(self , dev_map):
432+ self ._cache_lock = threading.Lock()
433+
434+ def get_or_create (self ):
435+ """ Return cached default SyclDevice, creating it if needed."""
436+ with self ._cache_lock:
437+ key = 0
438+ if key in self .__device_map__:
439+ return self .__device_map__[key]
440+ dev = select_default_device()
441+ self .__device_map__[key] = dev
442+ return dev
443+
444+ def _update_map (self , dev_map ):
435445 self .__device_map__.update(dev_map)
436446
437447 def __copy__ (self ):
@@ -441,37 +451,17 @@ cdef class _DefaultDeviceCache:
441451 return _copy
442452
443453
444- # no default, as would share a single mutable instance across threads and
445- # concurrent access to the cache would not be thread-safe. Using ContextVar
446- # without a default ensures each context gets its own instance.
447- _global_default_device_cache = ContextVar(
448- " global_default_device_cache" ,
449- )
450-
451-
452- cdef _DefaultDeviceCache _get_default_device_cache():
453- """
454- Factory function to get or create a default device cache for the current
455- context
456- """
457- try :
458- return _global_default_device_cache.get()
459- except LookupError :
460- cache = _DefaultDeviceCache()
461- _global_default_device_cache.set(cache)
462- return cache
454+ # all threads share the same cached default
455+ _global_default_device_cache = _DefaultDeviceCache()
463456
464457
465458cpdef SyclDevice _cached_default_device():
466- """ Returns a cached device selected by default selector.
459+ """
460+ Returns a cached device selected by default selector.
467461
468462 Returns:
469463 dpctl.SyclDevice:
470464 A cached default-selected SYCL device.
471465
472466 """
473- cdef _DefaultDeviceCache _cache = _get_default_device_cache()
474- d_, changed_ = _cache.get_or_create()
475- if changed_:
476- _global_default_device_cache.set(_cache)
477- return d_
467+ return _global_default_device_cache.get_or_create()
0 commit comments