# Raise if containers accessed while being "changed"?

**URL:** <https://forum.crystal-lang.org/t/raise-if-containers-accessed-while-being-changed/3937>\
**Category:** Crystal Contrib\
**Created:** [October 14, 2021, 6:30am UTC](https://forum.crystal-lang.org/t/raise-if-containers-accessed-while-being-changed/3937 "2021-10-14T06:30:57Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![rogerdpack](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rogerdpack/32/117_2.png) [@rogerdpack](https://forum.crystal-lang.org/u/rogerdpack)\
**Post date:** [October 14, 2021, 6:30am UTC](https://forum.crystal-lang.org/t/raise-if-containers-accessed-while-being-changed/3937/1 "2021-10-14T06:30:57Z")

</div>

I remember hearing of a “sad story” of somebody passing a Map through a channel in golang and multiple threads started using it, it corrupted the Map itself by doing simultaneous insertions. Seg faults, etc.

I think golang added some “primitive” double checks for this kind of behavior (e.g. panic if accessed while being mutated).

> [@MT schedulers impact](https://forum.crystal-lang.org/t/mt-schedulers-impact/214/26):
>
> I have a split brain on this topic. On one side, I hate “we should have safe types in multithreaded environment”. Multithreading IS THE PAIN and it is unavoidable! Even if we remove segfaults our programs will not magically became correct. Multithreaded program could be correct only if you thought about its correctness and used appropriate synchronization. Otherwise it will be crap, even it will not segfault. On the other side, Go’s builtin map panics if you try to access it in wrong way, ie w…

> <https://stackoverflow.com/questions/36167200/how-safe-are-golang-maps-for-concurrent-read-write-operations>

> **[Go 1.6 Release Notes - The Go Programming Language](https://go.dev/doc/go1.6)**

Would there be support for adding something similar in crystal?

While we’re at it, java does something similar, throws a “ConcurrentModificationException” if you mutate a Map or List while iterating over it (even in the same thread). Would there be support for adding something similar?

Wanting to decrease the potential of segfaults here…

Thanks for your thoughts.

Cheers!

---

<div class="post-metadata">

**Author:** ![rogerdpack](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rogerdpack/32/117_2.png) [@rogerdpack](https://forum.crystal-lang.org/u/rogerdpack)\
**Post date:** [October 15, 2021, 2:03am UTC](https://forum.crystal-lang.org/t/raise-if-containers-accessed-while-being-changed/3937/2 "2021-10-15T02:03:50Z")

</div>

It seems like it should either have tripwires or the structures by default be made thread safe? Somehow java avoids segfaults typically, I think this is part of how…

> <https://github.com/crystal-lang/crystal/issues/9548>
>
> I think one of the biggest roadblocks for MT Usage is SafeHash and SafeArray.
> 
> …
> I've been playing around with some concepts together with suggestions from @bcardiff. 
> 
> Array is here: https://github.com/NeuraLegion/mt\_helpers/blob/master/src/mt\_helpers/safe\_types/safe\_array.cr
> 
> \`\`\`crystal
> 
> class SafeArray(T)
> include Synchronizable
> 
> getter :inner
> 
> def initialize(@inner : Array(T) = Array(T).new) forall T
> @synchronize\_lock = Mutex.new(:reentrant)
> end
> 
> macro method\_missing(call)
> synchronize do
> @inner.{{call}}
> end
> end
> 
> def safe\_inner
> synchronize do
> @inner.dup
> end
> end
> end
> \`\`\`
> 
> Hash is here: https://github.com/NeuraLegion/mt\_helpers/blob/master/src/mt\_helpers/safe\_types/safe\_hash.cr
> 
> \`\`\`crystal
> class SafeHash(K, V)
> include Synchronizable
> 
> getter :inner
> 
> def initialize(@inner : Hash(K, V) = Hash(K, V).new) forall K, V
> @synchronize\_lock = Mutex.new(:reentrant)
> end
> 
> macro method\_missing(call)
> synchronize do
> @inner.{{call}}
> end
> end
> 
> def safe\_inner
> synchronize do
> @inner.dup
> end
> end
> end
> \`\`\`
> 
> This seems to be the minimal changes needing to make access to the structures safe.
> 
> Any feedback? 
> 
> P.S
> \`\`\`crystal
> module Synchronizable
> @synchronize\_lock = Mutex.new
> 
> protected def synchronize(lock : Mutex = @synchronize\_lock)
> lock.synchronize do
> yield
> end
> end
> end
> \`\`\`

---

<div class="post-metadata">

**Author:** ![funny-falcon](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/funny-falcon/32/159_2.png) [@funny-falcon](https://forum.crystal-lang.org/u/funny-falcon)\
**Post date:** [October 15, 2021, 4:49am UTC](https://forum.crystal-lang.org/t/raise-if-containers-accessed-while-being-changed/3937/3 "2021-10-15T04:49:18Z")

</div>

> Somehow java avoids segfaults typically

Because Java has uniform object representation and GC aware to multithreading.

It is quite difficult to get Segmentation Fault in GC environment, since object remains live until there is no pointers to.

But it doesn’t mean “thread safety”. “Thread safety” is about correctness at whole.  
For example:

> <https://stackoverflow.com/questions/3836680/data-race-in-java-arraylist-class/3836844#3836844>

> the structures by default be made thread safe

No. Protecting each struct field with something like mutex is slow. Protecting struct is either slow or not possible in Crystal.

FAST / LOWLEVEL/ SAFE / HANDY - choose three, but not four.

Crystal is FAST, LOWLEVEL and HANDY language. It could NOT be completely SAFE.  
You’ve heard of Rust? It is FAST, LOWLEVEL and tries to be SAFE. That is why it could NOT be HANDY.

Yep, Array/Hash could contain logic for non-deterministic race detection, like in Go or Java. They are relatively high-level construct, and they could hide some complexity behind.

But it could not be spread to any struct or class without noticable performance hit.

---

<div class="post-metadata">

**Author:** ![rogerdpack](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rogerdpack/32/117_2.png) [@rogerdpack](https://forum.crystal-lang.org/u/rogerdpack)\
**Post date:** [November 2, 2021, 6:25am UTC](https://forum.crystal-lang.org/t/raise-if-containers-accessed-while-being-changed/3937/4 "2021-11-02T06:25:09Z")

</div>

Nice, yeah seems Java ArrayList just uses some non deterministic “best effort” checks for concurrent modification. I guess that’s probably enough.

Java’s HashMap is a different animal. I think I’ll just focus on the “easy” checks for Hash (parallel reads OK, anything else not OK).

There could be some more aggressive checks possible. Java disallows modification from “other threads” while iterating over a HashMap, and disallows modifying it from the current thread as well, might be too painful? I don’t understand the internals enough there anyway so won’t worry about it for now.
