MMKV: Thread and Process Handling
Link to this article: MMKV: Thread and Process Handling - Hunting Feather's Blog - CSDN Blog
What is POSIX?
- Portable operating system interface, including the system API
- Defines the standard UNIX-based system interface and vision
- Defines the interface for creating and manipulating threads
POSIX threads are threads in the POSIX standard
- There are C++ threads, but generally POSIX threads are used pthread.h
There are multiple threads in Java to operate MMKV, which involves the underlying collection, what should I do?
- lock
thread operation
1. Thread creation
- pthread_create(&pid, 0, run, &i)
- Parameter 1: Thread ID pthread_t pid
- Parameter two: thread attributes
- Parameter three: thread method void* run(void *args)
- Parameter 4: The parameter int i of the run method = 100 => What about multiple parameters? Pass in a struct or object
2、pthread_join
- pthread_join(pid, 0) // wait for thread pid to execute
3. pthread_exit force stop, not recommended
thread synchronization
mutex
4. Use mutexes
queue q; //Queue// There will be problems in operating queue in multi-thread!
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, 0); // 初始化 pthread_mutext_lock(&mutex); pthread_mutext_unlock(&mutex); pthread_mutext_destory(&mutex); // 销毁
- Non-recursive lock, cannot be locked repeatedly => deadlock
5. How to solve the demand for reentrant locks?
- Pthread_mutextattr_t can set the mutex attribute
pthread_mutextattr_t attr; pthread_mutextattr_init(&attr); // attribute initialization pthread_mutexattr_settype(&attr, PTHREAD_MUTEXT_RECURSIVE); // set as recursive lock/reentrant lock pthread_mutext_init(&mutext, &attr); pthread_mutextattr_destory(&attr); // attribute destruction
mmkv package
4. C++ encapsulates the ThreadLock class => use the method equivalent to JUC Lock
- lock
- unlock
- The constructor initializes mutex and attributes
- destruction
5. How to avoid forgetting to use unlock?
- Encapsulate the ThreadLock class again
class Lock{ThredLock *lock; public: Lock(ThreadLock lock){ this->lock = lock; lock.lock(); } ~Lock(){ lock->unlock(); // 解锁 } }
use
void test(){ ThreadLock *tl = new ThreadLock(); Lock Lock(tl);// will be automatically destructed after exiting }
- ScopedLock is in mmkv
6. What does the template template class do?
- Equivalent to Java's generics
7. SCOPEDLOCK() is further encapsulated in mmkv
- Macro function: all uppercase
#define SCOPEDLOCK(lock) _SCOPEDLOCK(lock, __COUNTER__) xxx ScopedLock<declttype(g_instanceLock)> __scopedLock0(&g_instance);
- __COUNTER__ is a macro defined by the compiler, and each call +1 means that the macro function has been called several times
- Declttype takes the type and is used for generics
- Why do you want to encapsulate macro functions like this? =>
8. Where do you need to lock?
- At the point where mmkv is constructed, the MMKV object is obtained from the collection
- m_dic related getXXX()/putXXX()
multi-Progress
1. mmkv can ensure that the data operated by the main process and sub-processes can be accessed by the other party
file lock
2. What is a file lock (flock)?
- Process a and process b operate the same file, and the integrity and visibility of the data need to be guaranteed
- flock file lock to ensure file synchronization
#include <sys/file.h> int flock(int fd, int operation); operation: lock type LOCK_SH shared lock (read lock) LOCK_EX exclusive lock (write lock) LOCK_UN release lock LOCK_BN non-blocking request, default is blocking, can be: LOCK_SH|LOCK_BN, similar to tryLock() of JUC Lock
3. What are the requirements for designing file locks in mmkv?
- recursive lock
- The file lock is a state lock, there is no counter, and the lock is added n times, and all are released once it is released
- Lock Upgrade/Lock Downgrade
- Read lock (shared lock) is upgraded to write lock (mutual exclusion lock)
- lock downgrade
- Problem: flock supports lock upgrades, but process A and process B both hold read locks and must be upgraded to write locks, which will lead to a problem of waiting for each other => deadlock occurs
- File locks do not support recursive locks == locks will disappear directly, resulting in no support for lock downgrades
4. How to design the file lock in mmkv? How to package?
- Increase read lock, write lock counter
class FileLock{ size_t sharedLockCount; size_t exclusiveLockCount; bool doLock(LockType lockType, // lock type bool wait); // block or not} bool FileLock::doLock(LockType lockType, bool wait){ ->read lock ->sharedLockCount++ ->sharedLockCount>1 //already Read lock has been applied to achieve reentrancy, no need to lock return->exclusiveLockCount>0 // write lock has been applied and has not been released, read lock can no longer be returned->write lock->exclusiveLockCount++ ->exclusiveLockCount>1 // there are other write locks, not released return ->sharedLockCount>0 // the current process already holds a read lock, and then try to add a write lock (try non-blocking method). Possible failure: other processes hold the read lock, release the read lock by itself, and then add the write lock. avoid deadlock -> pass condition check -> flock -> }
- Process A acquires a read lock, then acquires a write lock, OK (lock upgrade is supported)
- Process A has a read lock, process B has a read lock, and process A has a write lock, no! Process A needs to release the read lock. Write lock again.
5. Both process A and process B have read locks, and process A directly writes locks. Why does it cause deadlock?
- Process A wants to write the lock (blocking mode), and will wait for process B to release the read lock
- Process B also wants to write the lock (blocking mode) at this time, and will wait for process A to release the read lock
- deadlock
reward
1. How to ensure that the log will not be incomplete due to crash?
- mmap, the operating system will guarantee
x