My second alternative was to just create a new temporary bitmap in each thread that needs to use the public bitmap, and simply tempBitMap = publicBitMap
This is the right approach. You can't write and read a bitmap at the same time. You should probably have two bitmaps active at the same time. One for writing, one for the readers. After each write you swap them. Note, that the readers must be done with the bitmap before writing can begin.
If you create a new bitmap for writing each time the hand-off becomes simpler but you now have the problem that you need to dispose each bitmap once it is no longer in use. If you don't do that you can very quickly run out of RAM because the GC does not recognize the existence of unmanaged memory buffers.
This is seeming to throw some exceptions and I feel like there's probably a better way anyway.
You should probably debug them. There's nothing fundamental why this wouldn't work.
I saw that you can lock specific bits / pixels that you need to use in the multiple threads and then release them once you're done with them, but does that prevent writing to the whole bitmap for the duration of the lock?
I don't know. This sounds like a very complex scheme. Having some regions readable and some writable would require quite an amount of coordination and you can never read a consistent full bitmap.
Just looking for the most efficient solution
That would be the two-bitmap model.