// SPDX-License-Identifier: Apache-2.0 OR MIT
#! [allow(clippy::undocumented_unsafe_blocks)]
#! [cfg_attr(feature = "alloc" , feature(allocator_api))]
#! [cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
#! [allow(unused_imports)]
use core::{
cell::{Cell, UnsafeCell},
mem::MaybeUninit,
ops,
pin::Pin,
time::Duration,
};
use pin_init::*;
#[ cfg(feature = "std" )]
use std::{
sync::Arc,
thread::{sleep, Builder},
};
#[ allow(unused_attributes)]
mod mutex;
use mutex::*;
pub struct StaticInit<T, I> {
cell: UnsafeCell<MaybeUninit<T>>,
init: Cell<Option<I>>,
lock: SpinLock,
present: Cell<bool>,
}
unsafe impl <T: Sync, I> Sync for StaticInit<T, I> {}
unsafe impl <T: Send, I> Send for StaticInit<T, I> {}
impl <T, I: PinInit<T>> StaticInit<T, I> {
pub const fn new(init: I) -> Self {
Self {
cell: UnsafeCell::new(MaybeUninit::uninit()),
init: Cell::new(Some(init)),
lock: SpinLock::new(),
present: Cell::new(false ),
}
}
}
impl <T, I: PinInit<T>> ops::Deref for StaticInit<T, I> {
type Target = T;
fn deref(&self ) -> &Self ::Target {
if self .present.get() {
unsafe { (*self .cell.get()).assume_init_ref() }
} else {
println!("acquire spinlock on static init" );
let _guard = self .lock.acquire();
println!("rechecking present..." );
std::thread::sleep(std::time::Duration::from_millis(200 ));
if self .present.get() {
return unsafe { (*self .cell.get()).assume_init_ref() };
}
println!("doing init" );
let ptr = self .cell.get().cast::<T>();
match self .init.take() {
Some(f) => unsafe { f.__pinned_init(ptr).unwrap() },
None => unsafe { core::hint::unreachable_unchecked() },
}
self .present.set(true );
unsafe { (*self .cell.get()).assume_init_ref() }
}
}
}
pub struct CountInit;
unsafe impl PinInit<CMutex<usize>> for CountInit {
unsafe fn __pinned_init(
self ,
slot: *mut CMutex<usize>,
) -> Result<(), core::convert::Infallible> {
let init = CMutex::new(0 );
std::thread::sleep(std::time::Duration::from_millis(1000 ));
unsafe { init.__pinned_init(slot) }
}
}
pub static COUNT: StaticInit<CMutex<usize>, CountInit> = StaticInit::new(CountInit);
fn main() {
#[ cfg(feature = "std" )]
{
let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0 )).unwrap();
let mut handles = vec![];
let thread_count = 20 ;
let workload = 1 _000 ;
for i in 0 ..thread_count {
let mtx = mtx.clone();
handles.push(
Builder::new()
.name(format!("worker #{i}" ))
.spawn(move || {
for _ in 0 ..workload {
*COUNT.lock() += 1 ;
std::thread::sleep(std::time::Duration::from_millis(10 ));
*mtx.lock() += 1 ;
std::thread::sleep(std::time::Duration::from_millis(10 ));
*COUNT.lock() += 1 ;
}
println!("{i} halfway" );
sleep(Duration::from_millis((i as u64) * 10 ));
for _ in 0 ..workload {
std::thread::sleep(std::time::Duration::from_millis(10 ));
*mtx.lock() += 1 ;
}
println!("{i} finished" );
})
.expect("should not fail" ),
);
}
for h in handles {
h.join().expect("thread panicked" );
}
println!("{:?}, {:?}" , &*mtx.lock(), &*COUNT.lock());
assert_eq!(*mtx.lock(), workload * thread_count * 2 );
}
}
Messung V0.5 in Prozent C=100 H=75 G=88
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-19)
¤
*© Formatika GbR, Deutschland