Something Is Weird About Rust's Threading and Concurrency | Rust Multi-Threading Tutorial

Ғылым және технология

Concurrency and synchronization is an extremely important topic in computer programming. How can I use multi threaded code to execute computationally intensive algorithms? While it's easy to do in most languages, designing a system that allows systems to access the same data at the same time is dangerous and easier said than done.
In this video I teach Multi Threaded Rust Programming, and use a more complicated example to describe how to provide multiple threads access to the same data.
Low Level Merch!: www.linktr.ee/lowlevellearning
Follow me on Twitter: / lowlevellearni1
Follow me on Twitch: / lowlevellearning
Join me on Discord!: / discord

Пікірлер: 132

  • @scheimong
    @scheimong2 жыл бұрын

    The Mutex contains the data (and therefore owns the data), but who owns the Mutex when we are passing it into threads? Without answering this question Rust cannot automatically free its allocation correctly. Therefore we need Rc as a way to implement shared ownership; also we need the reference counting to be atomic to be thread-safe, ergo Arc. So in the end, it's Arc. All pieces come nicely together and it all makes sense. It might seem complicated at first glance, but it's correct. This is what I love about Rust.

  • @scheimong

    @scheimong

    2 жыл бұрын

    Edit: since this comment is getting pinned (thank you), I thought I'd add a bit more detail for completeness' sake. Note that although this is the canonical way to share a `Mutex` in Rust, it isn't the only way. If you can somehow create a `Mutex` that is guaranteed to outlive the execution of the thread (which isn't trivial), then the thread can simply borrow it without using `Arc`. One potential use case is if you have a long-living resource (as in, is valid for the entire duration of program execution; or in Rust-speak, having a `'static` lifetime), you can use `Box::leak` to release it from Rust's memory management, then pass it into threads by reference and it should work as expected. Practise caution though, because the resources you leaked will not be freed until your program terminates, as the name suggests. It is also possible to do this without leaking memory, although you would have to create a "scoped thread" (with third-party crates, `crossbeam` for example) to guarantee to the compiler that the `Mutex` you are sharing by reference indeed outlives the thread. Check it out if this floats your boat. Update: as of 1.63.0, scoped thread has now been incorporated into the standard library 🎉

  • @rumplstiltztinkerstein

    @rumplstiltztinkerstein

    2 жыл бұрын

    Important detail to add. Threading doesn't work in webassembly. We have to use the promise system. Async code is converted into promises as well.

  • @rumplstiltztinkerstein

    @rumplstiltztinkerstein

    2 жыл бұрын

    @@scheimong If we use ```Arc::downgrade```instead of ```Arc::clone```` it creates a weak reference instead of another arc pointer. Weak references are freed from memory when the original is released.

  • @stomah9832

    @stomah9832

    2 жыл бұрын

    there’s no need for reference counting because the threads are joined before couner is destroyed. this is what i hate about rust - it forces you to use bad abstractions with overhead, external crates for things that should be part of the language, or unsafe (most tutorials don’t do that)

  • @scheimong

    @scheimong

    2 жыл бұрын

    @@stomah9832 Ah hah. You would be, to quote Jack O'Connor who had an excellent video on this, "99% correct". You overlooked the fact that `thread::spawn` *CAN* fail, which will cause the `Mutex` to be freed if not enclosed within `Arc`, while other threads still critically depend on it. So Rust is technically correct to complain here.

  • @johnstanford7240
    @johnstanford72402 жыл бұрын

    Also FYI, for most primitive types, Rust has atomic primitives and they can be much faster. Instead of `Arc`, you can use `Arc`.

  • @mbartelsm

    @mbartelsm

    2 жыл бұрын

    That applies if you want each thread to do a single atomic operation on the value. If you want more complex logic you still need a mutex

  • @kepler69c32

    @kepler69c32

    2 жыл бұрын

    if it is possible to compile with builtin atomic operations, it means that your cpu can operate them. idk what happens with a primitive cpu that doesn't include them

  • @zanehannan5306

    @zanehannan5306

    2 жыл бұрын

    Depending on your use, you could also use an arc-swap::ArcSwap, or left-right::new_from_empty - but depends wholly on your use case. For some cases, arc-swap will be best (it's effectively a read-safe swappable value), for more a left-right reader-writer pair will be best (very fast), and for even more you can hold onto an &AtomicUsize or just ... use a sum of joins, if that's what's needed.

  • @sodiboo

    @sodiboo

    2 жыл бұрын

    ​@@kepler69c32 From reading the std::atomic docs, it seems that Rust just doesn't allow usage of atomic types on unsupported platforms

  • @31redorange08

    @31redorange08

    Жыл бұрын

    He used i32, not usize.

  • @Buzzec9101
    @Buzzec91012 жыл бұрын

    I've been doing rust for 5 years and specialized in concurrency. The coolest things I've found are atomics, they unlock a whole world of efficient parallel computing. Feel free to reach out if you want to talk about concurrency stuff

  • @bjugdbjk

    @bjugdbjk

    2 жыл бұрын

    5 yrs of rust exp ...awesome !!! I am senior Android dev for 5 yrs :) And I am planning to switch my career to Rust !! basically I am moving to Rust for 2 reasons ..i just love the language felt so good ..secondly I want to get a complete remote role ....So what do u say for getting a remote role rust will be a good option ?

  • @bjugdbjk

    @bjugdbjk

    2 жыл бұрын

    By the way !! Do u have any pointers to learn the concurrency stuff ?

  • @mishikookropiridze

    @mishikookropiridze

    2 жыл бұрын

    @@bjugdbjk There are not many jobs for rust.

  • @caret4812

    @caret4812

    Жыл бұрын

    they are not rust inventions though

  • @nishanth6403

    @nishanth6403

    Жыл бұрын

    Note that atomics are not limited to rust or neither were created first by rust. C++ 11 (and even before) has been using that for a long time.

  • @shadamethyst1258
    @shadamethyst12582 жыл бұрын

    You can also pass the mutex as a reference, but one limitation of thread::spawn is that it requires the 'static lifetime, which you can't achieve without leaking memory in your example. Thankfully there are libraries that help bridge that gap, like scoped_threadpool

  • @steffahn

    @steffahn

    Жыл бұрын

    Since August 2022, there's scoped threads API in the standard library, too :-)

  • @SandwichMitGurke
    @SandwichMitGurke2 жыл бұрын

    Perfect timing. Having a lecture about concurrency for the last few weeks and wanted to know how it works in Rust :)

  • @berylliosis5250

    @berylliosis5250

    2 жыл бұрын

    In more detail, it's controlled by the Send and Sync traits. Send allows you to send a value between threads, with ownership. An example of something that is not Send is Rc, because it does non-atomic increments of the reference counts, and sending that across threads could cause data races. Sync allows you to send a reference to a value across threads (although without scoped threads, it needs to be 'static). An example of something that is not Sync is RefCell; passing a &RefCell gives unsynchronized mutable access to the contents (as RefCell does not atomically control access). By default, types are determined Send and Sync by their composition. That is, a type that only contains Send/Sync fields will be Send/Sync.

  • @madscientist7430
    @madscientist74302 жыл бұрын

    great video! explained it well and in an interesting way. seemed a bit too basic to me though, i feel like anyone with basic knowledge of either rust or concurrency would know all of this. maybe do some videos on more complex concurrency in rust? i'd love to see that!

  • @LowLevelLearning

    @LowLevelLearning

    2 жыл бұрын

    Sounds like a plan

  • @jcbritobr
    @jcbritobr8 ай бұрын

    Just use scoped threads and you will can borrow the thread vector.

  • @misobarisic4013
    @misobarisic40132 жыл бұрын

    Closures and their data capturing (move) forced me to learn about refcells, rcs and arcs. I almost formed a habit of moving everything from the main scope into a refcelled rc just to be safe for the future. 😅

  • @FrancescoBochicchio-ly6du
    @FrancescoBochicchio-ly6duАй бұрын

    I'm just playing with Rust, but in mt early attempts to use threads, I found that declaring the mutex as static also works, without using Arc. After all, you do not need to mutate the mutex, only its contents.

  • @Echo_of_Abyss
    @Echo_of_Abyss2 жыл бұрын

    Thank you, now my headache can go away temporarily!

  • @user-ic1ku9np6h
    @user-ic1ku9np6h2 жыл бұрын

    You might want to use a scoped thread to avoid Arc to achieve less allocation.

  • @Dygear
    @Dygear2 жыл бұрын

    Thanks!

  • @ThePhiliposophy
    @ThePhiliposophy2 жыл бұрын

    Your content is gold and you have a good way of explaining things. Keep 'em coming!

  • @TiroM17
    @TiroM172 жыл бұрын

    i believe you could've covered what it means to "join a thread"

  • @colinmaharaj
    @colinmaharaj2 жыл бұрын

    Been doing this for 10 years in C++ Builder

  • @jerrody5400
    @jerrody54002 жыл бұрын

    Doesn't need to return a value explicitly. Like in this case, where `main` function returns `unit` type (aka `void`). If you return a value don't need to write the code like this: `return 5;` Need to write this code: `5`

  • @m.sierra5258

    @m.sierra5258

    2 жыл бұрын

    As this might be confusing without context: rust adheres to the principle that every block has a value. That value is the value of the last line, if the last line is written without a semicolon. That allows for a very functional programming style. So returns should be avoided as much as possible in general and replaced by multiple branches, multiple match cases or similar.

  • @TiroM17
    @TiroM172 жыл бұрын

    I like the video format a lot, byte-sized concepts of rust. yet i would prefer there to be less stock footage / less switching between them. i find this to be mentally straining and distracting

  • @TillmannHuebner
    @TillmannHuebner2 жыл бұрын

    You saved alot of people alot of headhache. I had to learn this the hard way

  • @MrAnandml
    @MrAnandml2 жыл бұрын

    Great video

  • @davidmccormack99
    @davidmccormack992 жыл бұрын

    The following might seem like nitpicking but there is a critical point at stake here… You are saying “concurrency” here but because you are talking about mutexes and sync issues associated with multiple threads, I think it would be much clearer to say “parallelism”. A program may utilise concurrency without creating multiple threads, i.e. without any parallelism. In other words, while parallelism implies that there is concurrency, the reverse is not true. And crucially from the perspective of what you’ve presented here, concurrency without parallelism has the major benefit of supporting lock-free algorithms and data structures. Mutexes or other sync mechanisms are only necessary in the context of concurrency achieved through parallelism, not concurrency generally. Speaking of other sync mechanisms, a smaller point I wanted to mention is that if the requirement is just to sync access to a counter, it would be very inefficient in C/C++ to achieve this using a blocking mutex. It would be better to use an interlocked memory access API which provides an ability to atomically increment a counter in a thread-safe way using special CPU instructions. All of the major instruction set architectures in use today support interlocked memory access. The C++ Standard Library exposes the OS-specific interlocked API through the various templates and specialisations in the header. I’m sure Rust has an equivalent. Edit: I’ve just seen that another commenter has mentioned the Rust equivalent to .

  • @TON-vz3pe

    @TON-vz3pe

    Жыл бұрын

    Thanks for the nice explanation. Others were talking about scoped threadpool. Do you know what it is?

  • @davidmccormack99

    @davidmccormack99

    Жыл бұрын

    @@TON-vz3pe Not sure what they’re referring to - there certainly isn’t any std::scoped_thread class template. Generally though, when C++ devs talk about a “scoped _____” they mean a class that uses the RAII pattern, i.e. a class whose instances own some resource and whose destructor will free/release/close/delete that resource. I can only guess then that a scoped thread pool refers to a facility whereby a thread can be leased from a thread pool to do some background work, and where the thread is returned to that pool on destruction of an object. I’ve implemented something like that a few times.

  • @dynfoxx

    @dynfoxx

    Жыл бұрын

    @@TON-vz3pe Scoped threads refers to a safe way to access stack variables in Rust. Since threads are technically there own lifetime close to static you would normally need to move everything. However a scoped thread shortens that lifetime making it possible to just pass references and not copy/move. A pool of these would just pull from already spawned threads instead of creating new ones. One thing you may find odd is that they are done in the form of functions and closures. This is due to the fact that drop is not garenteed in Rust or any other language.

  • @NewEnglandMovies
    @NewEnglandMovies2 жыл бұрын

    Is this primarily going to be a Rust channel now?

  • @jonathanmoore5619

    @jonathanmoore5619

    2 жыл бұрын

    I hope so.

  • @LowLevelLearning

    @LowLevelLearning

    2 жыл бұрын

    Nope! Just dipping my toes in some new topics that have been interesting me. What topics do you like most?

  • @mehmetfurkandogan9057

    @mehmetfurkandogan9057

    2 жыл бұрын

    @@LowLevelLearning HPC!

  • @NewEnglandMovies

    @NewEnglandMovies

    2 жыл бұрын

    @@LowLevelLearning ah no worries, just wondering when we're going to go back to arm64 assembly :) but it's ok if you don't! Just asking.

  • @johnstanford7240

    @johnstanford7240

    2 жыл бұрын

    I vote for all embedded Rust :)

  • @dj-maxus
    @dj-maxus Жыл бұрын

    Recently, I was trying to solve the same toy problem. Seemingly, it is possible to use AtomicUsize counter without wrapping it in Mutex

  • @jonathanmoore5619
    @jonathanmoore56192 жыл бұрын

    Nice video.

  • @arubaga
    @arubaga2 жыл бұрын

    Can you put a Rust Mutex into a structure and create that structure ahead of time and assign it to a static variable? Does this work around the mutex moving restriction?

  • @m.sierra5258

    @m.sierra5258

    2 жыл бұрын

    Rust does not allow code to be run before main. Therefore all global variables have to be trivially statically costructible. Therefore to implement your suggestion you would have to wrap the mutex in a lazy static variable, and then you would be able to access it from every thread. But that is also discouraged, because it is unclear when the lazy static mutex should be destroyed, or if it sounds be destroyed at all. Global variables is one of those C concepts that rust tries to un-learn programmers. It's much better, conceptually, to have a context object passed to every thread that contains a mutex smart pointer.

  • @dynfoxx

    @dynfoxx

    2 жыл бұрын

    You would most likely just use a scooped thread. You can take multiple references to it without moving it.

  • @m.sierra5258
    @m.sierra52582 жыл бұрын

    Great video! But would you mind removing the "return;" at the end of main? It is bad programming style and opposed to the functional base principle of "every block has a value", which rust adheres to. (opposed to blocks 'returning' a value)

  • @LowLevelLearning

    @LowLevelLearning

    2 жыл бұрын

    Good call!

  • @touisbetterthanpi

    @touisbetterthanpi

    2 жыл бұрын

    i think calling it "really bad programming style" is very hyperbolic.

  • @m.sierra5258

    @m.sierra5258

    2 жыл бұрын

    @@touisbetterthanpi well it's a redundant statement that does nothing and it carries over a concept from C that doesn't apply to Rust. So yes, I think it's bad programming style :)

  • @aragonnetje

    @aragonnetje

    2 жыл бұрын

    @@m.sierra5258 and some people prefer to have their return values specified more clearly, because it improves readability and provides a clear distinction between functions with a return value and functions simply modifying state :)

  • @m.sierra5258

    @m.sierra5258

    2 жыл бұрын

    @@aragonnetje In my experience it becomes very natural. Because return only works with functions; if you want to pass values out of if or match statements, or blocks in general, the way of writing it with a statement without semicolon becomes second nature.

  • @thanatosor
    @thanatosor2 жыл бұрын

    using shared data in multi threading on Rust, is like you need to open a box before each thread dropping coin into it.

  • @motbus3
    @motbus3 Жыл бұрын

    Nice video. But you used concurrency and parallelism in similar way but there is a distinction there. Anyway! Thanks!

  • @rodneylives
    @rodneylives2 жыл бұрын

    It's weird, on my Android tablet, this video seems to have an encoding error? It's split vertically, and has some display glitches. Probably a problem on KZread's end?

  • @jabuci
    @jabuci Жыл бұрын

    You don't need to return at the end of main(). When you reach the end of main(), the program finishes.

  • @dougsteel7414
    @dougsteel74142 жыл бұрын

    "passing into threads" - how does that actually function and presumably it's hardware specific. I think this is very difficult to monitor, perhaps what you'd need is to create computational load and somehow have a minimally interfering cycles/n report and go over it. I would be very grateful because I lack patience but really like your channel 👍

  • @digama0

    @digama0

    2 жыл бұрын

    The underlying mechanism of thread::spawn is that it gets a block of memory (a closure which owns some state, which is to be "sent" to the other thread) and to share it, the memory is put on the thread's stack after initialization. (This is just a memcpy of the data stored in the closure itself into the thread's memory, not a deep copy.) A closure is just a struct containing all the data that was captured from the enclosing context (in this case, an Arc which is just a pointer sized value, so it is probably not even passed in memory but rather via registers, so the register simply has to be written to the thread stack once), and that struct implements the call operator which is called from the thread once it is initialized. If the thread is running from another core, that means that while the Arc itself is in the core's private memory, the stored u32 is in shared memory and the two cores battle it out using a cache coherence protocol whenever they want to make changes to it. (This is actually not all that hardware-specific up to this point; the cache coherence protocol can vary depending on the architecture though.)

  • @autarchprinceps
    @autarchprinceps11 ай бұрын

    This is about the least rust way of coding in so few lines you can achieve.

  • @mikhalpalych
    @mikhalpalych7 ай бұрын

    Oh, so easy to remember now

  • @k98killer
    @k98killer11 ай бұрын

    Q: Do you pass by reference or by value? A: Yes.

  • @Codeaholic1
    @Codeaholic12 жыл бұрын

    Seriously missed opportunity to talk about the Send and Sync marker traits.

  • @alexb.9806
    @alexb.980611 ай бұрын

    Incrementing ints using mutexes... Uh. There is no any profit in this since it just linearised every thread. There are at least two better options to perform concurrent sum, like using atomic increments or thread locals.

  • @bazoo513
    @bazoo51310 ай бұрын

    1:33 - Umm why the 0..10 loop does not produce 11 instances of "Hello, World!" ? Is rust semantics of ranges different from other languages?

  • @jcm2606

    @jcm2606

    6 күн бұрын

    `a..b` ranges are exclusive, meaning that they go from `a` to `b - 1`. If you want an inclusive range, where it goes from `a` to `b`, then you'd use an `a..=b` range.

  • @michaelmueller9635
    @michaelmueller9635 Жыл бұрын

    Is there in Rust something similar to threading and multiprocessing in Python? Like shown here: threading vs multiprocessing in python - KZread kzread.info/dash/bejne/c46iqbSEdri7YMY.html Or is the process of ownership and borrowing in Rust automatically avoiding these pitfalls by design? Are there costs in efficiency for this?

  • @ClearerThanMud
    @ClearerThanMud2 жыл бұрын

    Nice work. In idiomatic Rust you would more likely see something like let handles: Vec = (0..10).map( |i| ... ).collect(); but I'm guessing you were concerned that your audience might not be familiar with map and collect.

  • @31redorange08
    @31redorange08 Жыл бұрын

    2:49 Your counter variable vanished.

  • @Benjo1102
    @Benjo1102 Жыл бұрын

    I tried to teach myself Rust last month. But I find its syntax rather haunting.

  • @LowLevelLearning

    @LowLevelLearning

    Жыл бұрын

    You can do it!

  • @roxferesr
    @roxferesr2 жыл бұрын

    Yikes, rust code is not as elegant as I’d imagined

  • @1over137
    @1over137 Жыл бұрын

    Eugh... that's nasty.

  • @PremierSullivan
    @PremierSullivan2 жыл бұрын

    Why use mutexes? Atomics are so much better! Mutexes are actually implemented via the atomic features of the CPU, so you're basically using an abstraction to make things worse. Seriously just use atomics.

  • @peter9477

    @peter9477

    2 жыл бұрын

    If you have a struct with multiple fields that need to be read or modified in atomic fashion (together) you still need the Mutex. Atomic primitives are fine, of course, as long there's no need to keep them synchronized with each other.

  • @FreeDomSy-nk9ue
    @FreeDomSy-nk9ue2 жыл бұрын

    0:21 This C code is not cross platform and only works on systems that support POSIX thread (not Windows, for example) Point is, you can't compare it to the Python code mentioned a few frames before it.

  • @Murderbot2000
    @Murderbot20002 жыл бұрын

    I thought I was in the know. After watching this, I don’t know jackshit.

  • @NootNooot
    @NootNooot2 жыл бұрын

    Rust beats every language

  • @raffimolero64

    @raffimolero64

    2 жыл бұрын

    Depends. Creating as many segfaults as possible? C and C++ beat Rust by a huge margin.

  • @KangJangkrik

    @KangJangkrik

    2 жыл бұрын

    Wow rust community seems hate C a lot

  • @yb9737

    @yb9737

    Жыл бұрын

    ​@@raffimolero64 only if you don't know how to code. Please don't touch a sharp knife if you cant even handle a wooden stick.

  • @DooMWhite

    @DooMWhite

    Жыл бұрын

    @@yb9737 Wow, you must put all the Microsoft, AWS, and Apple engineers to shame, cuz they have made and still make lots of memory errors. Truth be said, most of the errors in their softwares are those!

  • @gideonunger7284
    @gideonunger7284 Жыл бұрын

    The thing is that this doesnt help me at all as a game developer. Mutexes are orders of magnitude to slow for any rendering code and its type system cant express most safe access patterns. so most code would have to be unsafe anyway and unsafe rust is arguably worse than regular c++.

  • @tomtravis858

    @tomtravis858

    Жыл бұрын

    I'd be very surprised if the performance overhead of a mutex would be noticeable for the vast majority of applications, could you link me some code written in c++ which mutexes would fail to be performant for? I'd love to test it.

  • @gideonunger7284

    @gideonunger7284

    Жыл бұрын

    @@tomtravis858 ? As i said games. Locking a mutex takes for ever in the context of tight loops. Often atomic operations are already to slow bc of the CPU pipeline stalls they introduce.

  • @tomtravis858

    @tomtravis858

    Жыл бұрын

    @@gideonunger7284 I don't see how game code is magically different than any other kind of code, and I've never had issues with the limited ray caster I made.

  • @gideonunger7284

    @gideonunger7284

    Жыл бұрын

    @@tomtravis858 man i have no clue what you are talking about. You not being very educated on this topic isn't my problem.

  • @tomtravis858

    @tomtravis858

    Жыл бұрын

    @@gideonunger7284 sound like a you problem I'm gonna be honest 🤷 what I said is completely readable for normal people, have fun though.

  • @mattstyles4283
    @mattstyles4283 Жыл бұрын

    This is so unnecessarily complex😅 And people think Java is hard lol

  • @dynfoxx

    @dynfoxx

    Жыл бұрын

    Not sure if this is a joke or not. Just incase it's not this is not a limitation of rust. It's how OS level locks work and is a restriction in all languages.

  • @jogurtnaturalny
    @jogurtnaturalny Жыл бұрын

    WOW, I just watched it, and I hate it. Concurrency is something in rust that feels like a poor copy from C lib. GoLang ( I code in Go, btw ) handles concurrent programs way better. ( In my opinion, based on this video ).

  • @dynfoxx

    @dynfoxx

    Жыл бұрын

    This is parallelism not concurrency. Rust has async for concurrency. While Rust is a bit different it uses the same building blocks as C and most others languages. The only difference is Rust checks to make sure it's correct at compile time.

  • @FrancescoBochicchio-ly6du

    @FrancescoBochicchio-ly6du

    Ай бұрын

    AFAIK, golang has no form of protection for data shared among goroutines. It is left to the programemr to make sure that data races do not occurr. Rust attempts to prevent data races at compiling time, and does that without introducing too much hassle, IMO.

  • @paulcosta8297
    @paulcosta82972 жыл бұрын

    Please say mutices (myootuhSeas) instead of "mutexes".

  • @merseyviking

    @merseyviking

    2 жыл бұрын

    Why? Mutex is a portmanteau of mutually exclusive and so doesn't necessarily follow the same rules as Latin-based words like vertex.

  • @peter9477

    @peter9477

    2 жыл бұрын

    Please don't. Most programmers will give you funny looks.

  • @funmath3835
    @funmath3835 Жыл бұрын

    shity rust.

  • @PetyrC90
    @PetyrC902 жыл бұрын

    I will tell a joke: Coding with Rust.

  • @stomah9832
    @stomah98322 жыл бұрын

    AND WHY DOES IT NEED TO BE REFERENCE COUNTED WHEN THE THREADS WILL BE JOINED BEFORE COUNTER IS DEALLOCATED? DISLIKE

  • @alireda640

    @alireda640

    Жыл бұрын

    When you spawn a function in rust you can't reference any variable without moving it to the new thread making it unaccessible to the main thread So in the first iteration of the loop the mutex is moved to a thread and the main function loses access to it So in the next iteration the mutex will not exists resulting in an error

  • @alireda640

    @alireda640

    Жыл бұрын

    Therefore you have to used reference counted to access the mutex

  • @steffahn

    @steffahn

    Жыл бұрын

    You actually don't need the reference counting. You just need to use a different thread spawning API that properly enforces that all threads are joined (i.e. waited for) before the referenced object is destroyed. Such API has existed for a long time in external crates, and since August 2022 we also have a standard library version of it. See the std::thread::scope function.

  • @trevise684
    @trevise6849 ай бұрын

    every time i look at rust, i am disgusted, i do understand why this language appeals to people. its terrible, looks at for 3 seconds and tell me its not an esolang

  • @Amine-gz7gq
    @Amine-gz7gq2 ай бұрын

    this language looks horrible