CppCon 2018: Geoffrey Romer “What do you mean "thread-safe"?”

Поділитися
Вставка
  • Опубліковано 18 жов 2024

КОМЕНТАРІ • 45

  • @tourdesource
    @tourdesource Рік тому +2

    Definitely a talk that has to be watched more than once...

  • @sanjuuyonsai
    @sanjuuyonsai 6 років тому +17

    18:11 std::function is like a pointer. Just because the std::function object is const does not mean the wrapped call is a const call. It is like a const pointer to a non-const object.
    I'm surprised this example is worth mentioning.

  • @KarelDonk
    @KarelDonk 6 років тому +6

    If you decide to fix std::function and make it const correct, then make it "noexcept correct" as well.

  • @cppmsg
    @cppmsg 5 років тому +12

    Please don't lean your laptop on the microphone shaft. Every movement causes rumble on the mic.

  • @Voy2378
    @Voy2378 6 років тому +10

    At 25:50 presenter makes a small but important mistake. [] for maps and sets does not behave like that.

    • @mdunkman
      @mdunkman 5 років тому +3

      He discusses it during comments around 50:00.

  • @Voy2378
    @Voy2378 6 років тому +6

    Also vector example explanation is too complicated. Problem is that vector stores bools using 1 bit/bool(as bitmasks) and CPUs can not atomically access specific bit.

    • @benjaminbrock1739
      @benjaminbrock1739 6 років тому +4

      No, it's more than that. He only alludes to this, but the point is that you have no guarantee on the reference type returned by operator[] and how it will mutate the object, whether it's thread compatible. You'd normally expect operator[] to return T&, but for std::vector it's std::_Bit_reference.

    • @Voy2378
      @Voy2378 6 років тому +1

      @@benjaminbrock1739 all you said is true, but that does not change what I am saying. You can not make vector be space efficient and have nonlocking calls to [2] and [5] that are thread safe. In other words it is not about vector being defective... You can not do this because HW does not allow it. This is the reason why standard also says bitfields are big nono when it comes to thread safety.

    • @benjaminbrock1739
      @benjaminbrock1739 6 років тому +3

      Sure, absolutely.
      But I think the point is that when you're in the wild looking at some random::vector, where you would normally assume operator[] to be thread compatible, you don't really know that unless you examine the reference type it returns and see if it has thread compatibility guarantees or could cause an "API race."

    • @MatthijsvanDuin
      @MatthijsvanDuin 5 років тому +4

      Actually, most CPUs do support atomic bit set/clear operations, though obviously at a performance cost.

    • @TheMrKeksLp
      @TheMrKeksLp 4 роки тому +2

      @@MatthijsvanDuin They also support atomic OR and AND which are enough to implement a lockless bitset

  • @yanzhuowang4987
    @yanzhuowang4987 4 роки тому

    At 13:50, how is there no API race? "Whatever" can read "shared_int" while "Thingy" writes to it. There's no guarantee that int write operation is thread-safe on all architectures.

    • @yanzhuowang4987
      @yanzhuowang4987 4 роки тому +1

      After seeing the next slide, I think he is missing a "const" in the "Thingy::foo" function signature.

    • @jonkalb2746
      @jonkalb2746 4 роки тому +11

      @@yanzhuowang4987 Recall that C++ is a value semantic language, so "Thingy::foo" is taking the int by value and modifying that int parameter is not modifying the original "shared_int," but is modifying a copy of it.

    • @jasonleo
      @jasonleo 4 роки тому +2

      Both shared int parameters are local copy of global int, so there's indeed no race

    • @BlairdBlaird
      @BlairdBlaird 2 роки тому

      @@yanzhuowang4987 `Thingy` takes the `int` by value, so internally it operates on a copy, not on the shared global.
      Now you could argue that reading an integer is not portably guaranteed to be atomic (even if alilgned, that's architecture-specific), however the point there was that all operations on the global were reads so performing them without synchronisation is safe.

  • @Wren6991
    @Wren6991 6 років тому +3

    1:30 how are concurrent writes of the same data to the same address unsafe? The order of writes is indeterminate, but isn't the result the same?

    • @knight024
      @knight024 6 років тому +4

      Usually memory is read or written in atomic units determined by the CPU architecture (32 bit and 64 bits item aligned on 32 bit and 64 bit boundaries is common these days).
      In this case, what happens depends on the amount of data being written.
      Let's consider the case of 32 bit atomic read/write cells.
      If two threads write 32 bits into such an aligned cell, then it is absolutely well defined what happens: one of the two written values is retained. Unfortunately for you (well, the program), you don't know which value. By extremely clever programming, you can actually use this atomicity of reads and writes to build synchronization algorithms (e.g., Dekker's algorithm), but it is faster typically to use architecturally defined locks instead.
      If two threads write more than an atomic unit (e.g., they both write a 128 bit value), then in fact the atomic unit sized pieces of the values written will be stored in a absolutely well defined way, but you won't know which pieces of which value get written in what order. So what may end up in storage is the value from the first thread, the second thread, or mixes of the bits in atomic unit sizes from both threads.
      Similar ideas hold for one thread reading, and one thread writing in atomic units, and larger.
      Basically, you don't want to do unsynchronized reads and writes to memory locations, because you won't know the outcome, even though it may be very well defined by the architecture.

    • @Wren6991
      @Wren6991 6 років тому

      @@knight024 I understand, but look at the code. The pointers are the same. Maybe the problem is that it's a silly toy example.
      You will have terrible performance because you're in cache snoop hell. You should get the same result as a single-threaded memcpy though.

    • @7xr1e20ln8
      @7xr1e20ln8 6 років тому

      Hmm, could be volatile memory

    • @Wren6991
      @Wren6991 6 років тому

      @@7xr1e20ln8 Array accesses will always generate memory accesses anyway (unless the index is provably constant) because you can't do indirect addressing on registers. Volatile would just give you a guarantee that the array accesses aren't reordered with respect to each other within a single thread of execution, and doesn't help us with this multithreaded example.

  • @ganaa72001
    @ganaa72001 6 років тому +1

    important

  • @TheMrKeksLp
    @TheMrKeksLp 4 роки тому +4

    At 4:59 that definitely is a data race. I don't know why he would doubt that. std::string isn't synchronized and in this case is likely going to reallocate while being accessed. That's literally a data race

    • @aitorperez4019
      @aitorperez4019 3 роки тому +6

      The standard specifies that a data race happens when two operations read and write from or to the same memory location concurrently. It does not specify anything about objects, and so, because std::string is an abstraction and not a built-in type, it is not a data race in the sense of the Standard. You would need to look underneath the hood to check if there is actually a data race. The example just aims to show that the standard does not comtemplate properly all cases in the definition, hence the definitions the people in Google use internally

  • @ennio5763
    @ennio5763 5 років тому +9

    Does he reads a text on his laptop ? That makes the tone of the presentation so much less lively.

  • @arsen3783
    @arsen3783 5 років тому

    I'd argue that memcpy is still safe in both those cases because you can still use it in two places, whether it's safe to use it in the same buffer is up to the caller.

  • @agnesakne4409
    @agnesakne4409 Рік тому

    Guy is only engineer not a sr engineer at google?

  • @bytefu
    @bytefu 2 роки тому +4

    So basically C++ type system is trash and cannot guarantee anything. The biggest problem is that "const" is not transitive. I switched to Rust a few years ago and don't miss C++ a tiny bit.

  • @7xr1e20ln8
    @7xr1e20ln8 6 років тому +17

    Been a C++ programmer for 15 years. I don't like the way C++ is going. I'll start using Rust where ever I could

    • @andreasfett6415
      @andreasfett6415 6 років тому +2

      I second that. Don't know if Rust is the answer (but that's not my point). With any new 1x, 2x versions sooo many pitfalls came with the new features and just nothing got simpler if you try to use it seriously in production code.
      Nicolai Josuttis' talk highlights one aspect, and if you look into others aspects it's just the same can of worms.
      Might be great for library implementers but for application development it's just a whole bunch of rules "Don't do that" you have to add with each new standard version. And that's just frustrating.

    • @DuRoehre90210
      @DuRoehre90210 6 років тому +1

      @@andreasfett6415 I would not fully agree. Some of the new additions in 0x (including lambdas) are pretty handy. But what I see in 17x looks mostly creepy. Instead of adding useful helpers like coroutines or async/await (maybe extending futures with nicer background thread interaction) they started inventing hairy things like string_view.

    • @andreasfett6415
      @andreasfett6415 6 років тому

      @@DuRoehre90210 I totally agree with you, that some of the additions to 0x are useful. But while lambdas are indeed very nice, they add their own set of problems you have to keep in mind (eg scoping issues). So again a set of rules which say "Don't do that". That's all nice for people that just have to learn the diff, but try using young programmers on C++ code bases. With each new standard version the learning curve just becomes steeper and code reviews more painful. As for coroutines, I already have nightmares about debugging code using them unless the gdb people come up with something really smart.

    • @MasterHigure
      @MasterHigure 5 років тому +4

      I've seen a decent amount of CppCon lectures on youtube lately, and basically half of them describe conventions you ought to follow in order to avoid problems which wouldn't compile in the first place in Rust. Data races (or "API races") is one such thing.

    • @zvxcvxcz
      @zvxcvxcz 3 роки тому

      @@MasterHigure I'm not a Rust programmer, but do those come with algorithmic restrictions? E.g. there are some things you can't do* at all in Java because it is sometimes unsafe even if your implementation is perfectly safe and correct.
      *in any reasonable way

  • @tommasobonvicini7114
    @tommasobonvicini7114 4 роки тому +2

    Things learned: if you are going for multithreading, you better be data-oriented rather than object-oriented.

  • @yaroslavpanych2067
    @yaroslavpanych2067 6 років тому

    Damn, he is deaf as hell!

    • @noxabellus
      @noxabellus 6 років тому +14

      No its the ridiculously thick accents, completely incomprehensible questions, and them not making _any_ effort to speak clearly.