this post was submitted on 30 Jan 2026
9 points (100.0% liked)

Learn Programming

2076 readers
12 users here now

Posting Etiquette

  1. Ask the main part of your question in the title. This should be concise but informative.

  2. Provide everything up front. Don't make people fish for more details in the comments. Provide background information and examples.

  3. Be present for follow up questions. Don't ask for help and run away. Stick around to answer questions and provide more details.

  4. Ask about the problem you're trying to solve. Don't focus too much on debugging your exact solution, as you may be going down the wrong path. Include as much information as you can about what you ultimately are trying to achieve. See more on this here: https://xyproblem.info/

Icon base by Delapouite under CC BY 3.0 with modifications to add a gradient

founded 2 years ago
MODERATORS
 

This question comes mainly from curiosity. I'm not quite sure how to phrase it best. Especially in a title. But I'm wondering if say you have one thread writing to a variable of an essentially primitive type and one thread reading them at the same time if there's any likelihood of the read happening while the variable is half written causing either weird values or undefined behavior.

Take something like a value of 8 bits from 00010101 to 11101000.

I'm imagining if say 4 bits are written while we try to read it the result could be something like

11100101

To play around i made this small sample rust. It passed without making garbage. Printing at first a bunch of lines stating "String = Hello!" and second "String = Hi!" without weirdness or issues. I kind of half-expected something like "String = #æé¼¨A" or a segfault.

use std::thread::{self, JoinHandle, sleep};

const HELLO: &str = "Hello!";
const HI: &str = "Hi!";

struct ExemptSyncStringSlice<'a>(&'a str);

unsafe impl Sync for ExemptSyncStringSlice<'_> {}

fn print_ptr(pointer: *const ExemptSyncStringSlice)
{
	for _ in 1..500
	{
		unsafe
		{
			println!("String = {}", (*pointer).0);
		}
	}
}

fn main()
{
	
	static mut DESYNC_POINTER: ExemptSyncStringSlice = ExemptSyncStringSlice(HELLO);

	let join_handle: JoinHandle<()> = thread::spawn
	(
		|| {
			print_ptr(&raw const DESYNC_POINTER);
		}
	);
	sleep(time::Duration::from_millis(1));
	unsafe { DESYNC_POINTER.0 = HI; }
	
	join_handle.join().unwrap();
}
you are viewing a single comment's thread
view the rest of the comments
[–] hendrik@palaver.p3x.de 2 points 1 week ago* (last edited 1 week ago)

Hehe, me too. I love microcontroller programming. That kind of forces you (at times) to think about the low-level stuff. And maybe have a look at the CPU datasheet once you go deep down. Something like an ESP32 or RP2040 has 2 CPU cores. And it's way easier to tell what happens compared to a computer with a complicated operating system in between, and an x86-64 CPU that's massively complicated and more or less just pretends to execute your machine instructions, but in reality it does all kinds of arcane magic to subdivide them, reorder things and optimize.

(Edit: And with C++ you get to learn all the dirty stuff... How it sometimes initializes variables to zero, sometimes it doesn't... It's your job to address memory correctly... Maybe one day I'll learn Rust instead of all the peculiarities of C++ 😆 And Rust support on microcontrollers is coming along, these days.)