Hello,
I am writing a framework in Cython using multi-process access to an LMDB 
database. I ran into a "Resource not available" error.
I isolated the problem in the following script (this is Cython calling 
the LMDB C API, so bear with the hybrid syntax):
import time
cimport cylmdb as lmdb # This is a Cython header mirroring lmdb.h
import multiprocessing
import threading
cdef:
     lmdb.MDB_env *env
     lmdb.MDB_dbi dbi
cdef void _check(int rc) except *:
     if rc != lmdb.MDB_SUCCESS:
         out_msg = 'LMDB Error ({}): {}'.format(
             rc, lmdb.mdb_strerror(rc).decode())
         raise RuntimeError(out_msg)
cpdef void get_() except *:
     cdef:
         lmdb.MDB_txn *txn
         lmdb.MDB_val key_v, data_v
     _check(lmdb.mdb_txn_begin(env, NULL, lmdb.MDB_RDONLY, &txn))
     key_v.mv_data = b'a'
     key_v.mv_size = 1
     _check(lmdb.mdb_get(txn, dbi, &key_v, &data_v))
     print((<unsigned char *>data_v.mv_data)[:data_v.mv_size])
     time.sleep(1)
     _check(lmdb.mdb_txn_commit(txn))
     print('Thread {} in process {} done.'.format(
             threading.currentThread().getName(),
             multiprocessing.current_process().name))
def run():
     cdef:
         unsigned int flags = 0
         #unsigned int flags = lmdb.MDB_NOTLS # I tried this too.
         lmdb.MDB_txn *wtxn
         lmdb.MDB_val key_v, data_v
     # Set up environment.
     _check(lmdb.mdb_env_create(&env))
     _check(lmdb.mdb_env_set_maxreaders(env, 128))
     _check(lmdb.mdb_env_open(env, '/tmp/test_mp', flags, 0o644))
     # Create DB.
     _check(lmdb.mdb_txn_begin(env, NULL, 0, &wtxn))
     _check(lmdb.mdb_dbi_open(wtxn, NULL, lmdb.MDB_CREATE, &dbi))
     # Write something.
     key_v.mv_data = b'a'
     key_v.mv_size = 1
     ts = str(time.time()).encode()
     data_v.mv_data = <unsigned char *>ts
     data_v.mv_size = len(ts)
     _check(lmdb.mdb_put(wtxn, dbi, &key_v, &data_v, 0))
     _check(lmdb.mdb_txn_commit(wtxn))
     print('Multiprocess jobs:')
     for i in range(5):
         multiprocessing.Process(target=get_).start()
     # Env should be closed only after all processes return.
     #lmdb.mdb_env_close(env)
If I execute run(), the first process runs successfully, but apparently 
it's holding on to some resources that the other processes need.
Multiprocess jobs:
b'1534691578.4300401'
Process Process-2:
Traceback (most recent call last):
   File "/usr/lib/python3.6/multiprocessing/process.py", line 258, in 
_bootstrap
     self.run()
   File "/usr/lib/python3.6/multiprocessing/process.py", line 93, in run
     self._target(*self._args, **self._kwargs)
   File "lakesuperior/sandbox/threading_poc.pyx", line 23, in 
lakesuperior.sandbox.threading_poc.get_
     cpdef void get_() except *:
   File "lakesuperior/sandbox/threading_poc.pyx", line 28, in 
lakesuperior.sandbox.threading_poc.get_
     _check(lmdb.mdb_txn_begin(env, NULL, lmdb.MDB_RDONLY, &txn))
   File "lakesuperior/sandbox/threading_poc.pyx", line 20, in 
lakesuperior.sandbox.threading_poc._check
     raise RuntimeError(out_msg)
RuntimeError: LMDB Error (11): Resource temporarily unavailable
Process Process-3:
Traceback (most recent call last):
   File "/usr/lib/python3.6/multiprocessing/process.py", line 258, in 
_bootstrap
     self.run()
   File "/usr/lib/python3.6/multiprocessing/process.py", line 93, in run
     self._target(*self._args, **self._kwargs)
   File "lakesuperior/sandbox/threading_poc.pyx", line 23, in 
lakesuperior.sandbox.threading_poc.get_
     cpdef void get_() except *:
   File "lakesuperior/sandbox/threading_poc.pyx", line 28, in 
lakesuperior.sandbox.threading_poc.get_
     _check(lmdb.mdb_txn_begin(env, NULL, lmdb.MDB_RDONLY, &txn))
   File "lakesuperior/sandbox/threading_poc.pyx", line 20, in 
lakesuperior.sandbox.threading_poc._check
     raise RuntimeError(out_msg)
RuntimeError: LMDB Error (11): Resource temporarily unavailable
Process Process-4:
Process Process-5:
Traceback (most recent call last):
   File "/usr/lib/python3.6/multiprocessing/process.py", line 258, in 
_bootstrap
     self.run()
   File "/usr/lib/python3.6/multiprocessing/process.py", line 93, in run
     self._target(*self._args, **self._kwargs)
   File "lakesuperior/sandbox/threading_poc.pyx", line 23, in 
lakesuperior.sandbox.threading_poc.get_
     cpdef void get_() except *:
Traceback (most recent call last):
   File "lakesuperior/sandbox/threading_poc.pyx", line 28, in 
lakesuperior.sandbox.threading_poc.get_
     _check(lmdb.mdb_txn_begin(env, NULL, lmdb.MDB_RDONLY, &txn))
   File "lakesuperior/sandbox/threading_poc.pyx", line 20, in 
lakesuperior.sandbox.threading_poc._check
     raise RuntimeError(out_msg)
   File "/usr/lib/python3.6/multiprocessing/process.py", line 258, in 
_bootstrap
     self.run()
   File "/usr/lib/python3.6/multiprocessing/process.py", line 93, in run
     self._target(*self._args, **self._kwargs)
   File "lakesuperior/sandbox/threading_poc.pyx", line 23, in 
lakesuperior.sandbox.threading_poc.get_
     cpdef void get_() except *:
RuntimeError: LMDB Error (11): Resource temporarily unavailable
   File "lakesuperior/sandbox/threading_poc.pyx", line 28, in 
lakesuperior.sandbox.threading_poc.get_
     _check(lmdb.mdb_txn_begin(env, NULL, lmdb.MDB_RDONLY, &txn))
   File "lakesuperior/sandbox/threading_poc.pyx", line 20, in 
lakesuperior.sandbox.threading_poc._check
     raise RuntimeError(out_msg)
RuntimeError: LMDB Error (11): Resource temporarily unavailable
If I run the same function multiple times on the same process, 
everything is fine.
Can someone point out what is wrong with this script?
Thank you,
Stefano