> On Sep 12, 2017, at 12:31 PM, John McCall via swift-evolution > <swift-evolution@swift.org> wrote: > >> >> On Sep 12, 2017, at 2:19 AM, Pierre Habouzit via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >> >>> On Sep 11, 2017, at 9:00 PM, Chris Lattner via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >>> >>> On Sep 4, 2017, at 12:18 PM, Pierre Habouzit <phabou...@apple.com >>> <mailto:phabou...@apple.com>> wrote: >>>> Something else I realized, is that this code is fundamentally broken in >>>> swift: >>>> >>>> actor func foo() >>>> { >>>> NSLock *lock = NSLock(); >>>> lock.lock(); >>>> >>>> let compute = await someCompute(); <--- this will really break `foo` >>>> in two pieces of code that can execute on two different physical threads. >>>> lock.unlock(); >>>> } >>>> >>>> >>>> The reason why it is broken is that mutexes (whether it's NSLock, >>>> pthread_mutex, os_unfair_lock) have to be unlocked from the same thread >>>> that took it. the await right in the middle here means that we can't >>>> guarantee it. >>> >>> Agreed, this is just as broken as: >>> >>> func foo() >>> { >>> let lock = NSLock() >>> lock.lock() >>> >>> someCompute { >>> lock.unlock() >>> } >>> } >>> >>> and it is just as broken as trying to do the same thing across queues. >>> Stuff like this, or the use of TLS, is just inherently broken, both with >>> GCD and with any sensible model underlying actors. Trying to fix this is >>> not worth it IMO, it is better to be clear that they are different things >>> and that (as a programmer) you should *expect* your tasks to run on >>> multiple kernel threads. >>> >>> BTW, why are you using a lock in a single threaded context in the first >>> place??? ;-) >> >> I don't do locks, I do atomics as a living. >> >> Joke aside, it's easy to write this bug we should try to have the >> compiler/analyzer help here for these broken patterns. >> TSD is IMO less of a problem because people using them are aware of their >> sharp edges. Not so much for locks. > > Maybe we could somehow mark a function to cause a warning/error when directly > using it from an async function. You'd want to use that on locks, > synchronous I/O, probably some other things.
Well the problem is not quite using them (malloc would e.g. and there's not quite a way around it), you don't want to hold a lock across await. > > Trying to hard-enforce it would pretty quickly turn into a big, annoying > effects-system problem, where even a program not using async at all would > suddenly have to mark a ton of functions as "async-unsafe". I'm not sure > this problem is worth that level of intrusion for most programmers. But a > soft enforcement, maybe an opt-in one like the Clang static analyzer, could > do a lot to prod people in the right direction. Sure, I'm worried about the fact that because POSIX is a piece of cr^W^W^W^Wso beautifully designed, if you unlock a mutex from another thread that the one locking it, you're not allowed to crash to tell the client he made a programming mistake. the unfair lock on Darwin will abort if you try to do something like that though. We'll see how much users will make these mistakes I guess. -Pierre
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution