BehindTheBarrier

joined 1 year ago
[–] [email protected] 2 points 7 months ago (2 children)

Sorry, but a long and slightly complicated question, for a hypotetical case.

I wanted to serve pages in my blog. The blog doesn't actually exist yet (but works locally, need to find out how I can safely host it later...), but lets assume it becomes viral, and by viral i mean the entire internet has decided to use it. And they are all crazy picky about loading times....

I haven't figued out the structure of the Page objects yet, but for the question they can be like the last question:

#[derive(Clone)]
pub struct Page<'a> {
    pub title: &'a str,
    pub endpoint: &'a str,
}

I wanted to create a HashMap that held all my pages, and when I updated a source file, the a thread would replace that page in the mapping. It's rather trivial of a problem really. I didnt find out if I could update a mapping from a thread, so I decided to make each value something that could hould a page and have the page object replaced on demand. It made somewhat sense since I don't need to delete a page.

There is a trivial solution. And it's just to have each HashMap value be a RwLock with an Arc holding my large string. No lagre string copies, Arc make it shared, and RwLock is fine since any number of readers can exist. Only when writing is the readers locked. Good enough really.

But I heard about DoubleBuffers, and though, why can't I have a AtomicPointer to my data that always exist? Some work later and I had something holding an AtomicPointer with a reference to an Arc with my Page type. But it didn't work. It actually failed rather confusingly. It crashed as I was trying to read the title on my Page object after getting it from the Arc. It wasn't even any thread stuff going on, reading once works, the next time it crashed.

struct SharedPointer<T> {
    data: AtomicPtr<Arc<T>>,
}

impl<T> SharedPointer<T> {
    pub fn new(initial_value: T) -> SharedPointer<T> {
        SharedPointer {
            data: AtomicPtr::new(&mut Arc::new(initial_value)),
        }
    }

    pub fn read(&self) -> Arc<T> {
        unsafe { self.data.load(Relaxed).read_unaligned() }.clone()
    }

    pub fn swap(&self, new_value: T) {
        self.data.store(&mut Arc::new(new_value), Relaxed)
    }
}

#[test]
pub fn test_swapping_works_2() {
    let page2: Page = Page::new("test2", "/test2");
    let page: Page = Page::new("test", "/test");
    let entry: SharedPointer<Page> = SharedPointer::new(page.clone());

    let mut value = entry.read();

    assert_eq!(value.title, page.title);
    value = entry.read();
    assert_eq!(value.title, page.title);

    entry.swap(page2.clone());

    let value2 = entry.read();
    assert_eq!(value2.title, page2.title);
    assert_eq!(value.title, page.title);
}

This has undefined behavior, which isn't too surprising since I don't understand pointers that much... and I'm actually calling unsafe code. I have heard it can produce unexpected error outside it's block. I'm just surprised it works a little. This code sometimes fails the second assert with an empty string, crashes with access violation, or one time it gave me a comparison where some of it was lots of question marks! My best understanding is that my Page or it's content is moved or deallocated, but odd that my Arc seems perfectly fine. I just don't see the connection between the pointer and Arcs content causing a crash.

I may just be doing the entire thing wrong, so sticking with RwLock is much better and safer since there is no unsafe code. But I seek to know why this is so bad in the first place. What is wrong here, and is there a remedy? Or is it just fundamentally wrong?

[–] [email protected] 2 points 7 months ago (3 children)

Hi,

Learning Rust and getting caught up in details, but I always want to know the whys of things, and the minor differences.

Lets start of with, is there a difference between the const value vs const reference?

// Given this little struct of mine, a Page with information about an endpoint
#[derive(Clone)]
pub struct Page<'a> {
    pub title: &'a str,
    pub endpoint: &'a str,
}

// Value
const ROOT_PAGE: Page = Page::new("Home", "/home");

// Reference
const ROOT_PAGE: &'static Page = &Page::new("Home", "/home");
  1. Since my functions always take a reference, is there any advantage to any of them. References are read-only, but since it's const it probably doesn't matter. What is prefered?

  2. I know String does allocations, while &str is a string slice or something which may be on the stack. Do I not end up making any allocations in this case since stucts are on the stack by default, and only hold the pointers to a string "slice". Especially given how they are made in this case.

  3. Is structs with references like this okay, this Page is constant but I'm going to make many "Pages" later based on the pages my blog has, as well as some other endpoints of course.

  4. If the struct is cloned, is the entire string as well, or just the pointer to the string slice? I assume it does copy the entire string, since to the best of my knowledge a &str does not do any reference counting, so deleting a &str means deleting it's content, not just the reference. Since that is the case, a clone will also copy the string.

  5. I am contemplating adding a "body" string to my Page struct. These string will of course be large and vary depending on the page. Naturally, I do not want to end up copying the entire body string every time the Page is cloned. What is the best course here, it kind of depends on the previous question, but is an Arc the solution here? There is only reading to be done from them, so I do not need to worry about any owner holding it.

[–] [email protected] 2 points 7 months ago

The peak might be higher for induction.

Not in the US, so electrical grid is different but induction on boost can use much more wattage for short periods, triggering the breaker. In my case the circuit was 16A if I remember correctly while a powerful induction should be on 25A.

[–] [email protected] 1 points 7 months ago

YouTube sometimes made it hard to find, but all channels do have an all videos Playlist. I think he button is on a profiles video page now. I don't know if yt-dlp can do only transcripts but I'm sure it can download all videos with transcripts included.

[–] [email protected] 8 points 7 months ago

Reminds me of folding cardboard boxes. If you are taking a flat piece and make a box of it, are you folding a box or unfolding the cardboard. Or both. And when you do the reverse, you do the same, do you not?

[–] [email protected] 25 points 7 months ago (5 children)

I don't think shorts are bad, but they aren't the reason I go to YouTube at all. They are just in the way.

[–] [email protected] 22 points 7 months ago (1 children)

Every time you open anything in office applications you get these small pop-ups

  • See what changes others did?
  • We added a new feature, do you want to see it?
[–] [email protected] 3 points 7 months ago (1 children)

I think it goes out of the cycle somewhat, kinda like all that is held up

If 100L rain down a day, and you use 10L for cooling then you will have still have 100L flowing but now only 90L for actual use. And then datacenters take up a significant amount of the total then you have a lot less to use elsewhere such as watering fields for example.

[–] [email protected] 2 points 7 months ago* (last edited 7 months ago) (4 children)

There used to be boxed ice cream with blueberry and egg yolk flavor. Loved it as a kid, got discontinued by the ice cream truck that had it. No replacement found. I probably won't even like it since I have forgotten the taste at this point.

[–] [email protected] 37 points 8 months ago (1 children)

Why wait and hope for C++ to get where modern languages are now? I know there's value in the shared experience in C++ that if adapted would make it stronger, but I can only see a development of C++ having to force a drop of a lot of outdated stuff to even get started on being more suitable.

But the language is just not comfortable to me. From large amounts of anything creating undefined behavior, the god awful header files which I hate with a passion, tough error messages and such. I also met a fun collision of C++ in Visual Studio and using it with CMake in CLion.

I've just started looking at rust for fun, and outside not understanding all the errors messages with the bounded stuff yet, figuring out what type of string I should use or pass, and the slow climb up the skill curve, it's pretty nice. Installing stuff is as easy as copy pasting the name into the cargo file!

Rust is just the prospective replacement of C++ though, people act like the White house said that C++ should be replaced by rust now. But the just recommend it and other languages, C# will do for a lot of people that does not need the performance and detail that the aforementioned languages target. Python is targeting a whole different use, but often combined with the faster ones.

C++ will live a long time, and if the popularity dies down it will surely be very profitable to be a developer on the critical systems that use it many years from now. I just don't think an evolution of C++ is going to bring what the world needs, particularly because of the large amount of existing memory related security vulnerabilities. If things were good as they are now, this recommendation would not be made to begin with.

[–] [email protected] 1 points 8 months ago

If you want a first in first out it's better than a list. Deque is also whats powering thread safe queues in python where you want said FIFO functionality when sending from one thread to another. (typically the order doesn't matter since it's threads, but generally speaking it makes more sense to take the first thing going in, out of it too.)

[–] [email protected] 7 points 8 months ago

It would kinda go along to "do not go gentle into the good night" like it was presented in Interstellar.

view more: ‹ prev next ›