First paste the Demo code:
// -------------------- Tmutex. h start ------------------------------
// Implement the Linux mutex C ++ Encapsulation
# Ifndef tmutex_h
# Define tmutex_h
# Include <pthread. h>
// Thread mutex
Struct threadmutex
...{
Threadmutex ()
...{
Pthread_mutex_init (& CTX, null );
}
~ Threadmutex ()
...{
Pthread_mutex_destroy (& CTX );
}
Inline void lock ()
...{
Pthread_mutex_lock (& CTX );
}
Inline void unlock ()
...{
Pthread_mutex_unlock (& CTX );
}
Pthread_mutex_t CTX;
};
// Empty mutex, that is, nothing is done when lock is called.
Struct nullmutex
...{
Inline void lock ()
...{
}
Inline void unlock ()
...{
}
};
Template <class T>
Class cautoguard
...{
Public:
Cautoguard)
...{
M_mtx.lock ();
}
~ Cautoguard ()
...{
M_mtx.unlock ();
}
Protected:
T & m_ctx;
};
# Define auto_guard (guard_tmp_var, mutex_type, CTX)
Cautoguard <mutex_type> guard_tmp_var (CTX)
# Endif
// ------------------------- Tmutex. h ended ------------------------------------------
// ------------------------- The main program file test. cpp starts ----------------------------------
# Include <pthread. h>
# Include "tmutex. H"
# Include <iostream>
Using namespace STD;
Typedef threadmutex mutex_type; // use the mutex type of thread mutex
// Typedef nullmutex mutex_type; // mutex type without mutex
Mutex_type g_gp; // mutex variable definition
Void * print_msg_thread (void * parg );
Void * print_msg_thread (void * parg)
... {// Working thread, simulating a job in a loop.
Char * MSG = (char *) parg;
Auto_guard (Gd, mutex_type, g_ctx );
For (INT I = 0; I <10; I ++)
...{
Cout <MSG <Endl;
Sleep (1 );
}
Return NULL;
}
Int main ()
...{
Pthread_t T1, T2;
// Create two working threads, 1st printing threads 10 1, and 2nd printing threads 10 2.
Pthread_create (& T1, null, & print_msg_thread, (void *) "1 ");
Pthread_create (& T2, null, & print_msg_thread, (void *) "2 ");
// Wait until the thread ends
Pthread_join (T1, null );
Pthread_join (t2, null );
Return 0;
}
// ------------------------------- The main program file test. cpp ends.
After reading the sample code and comments above, I believe I have understood the functions of the Code. We create two threads in the main program, 1st threads print 10 1 and 2nd threads print 10 2 in a loop. Due to the characteristics of the thread, the two threads may not be executed in order, and they may be scheduled and executed in turn.
If the two threads are scheduled to run in turn, the order of the printed 10 1 and 10 2 is not fixed. After thread 1 prints a few characters, it may not interrupt. the CPU is allocated to thread 2 for execution. This allows every thread to obtain CPU resources as much as possible. But it also brings about problems. If two threads access a variable together. Both threads modify the modification. If the modification is interrupted, the final Modification result is inconsistent with the Expected One. For an operation that cannot be interrupted, we call it an atomic operation. To make a code segment in a thread an atomic operation, we have to use mutex. As shown in this example, if we do not use mutex, the printing order will be destroyed. After the mutex is used, thread 1 does not leave the region managed by the mutex, thread 2 cannot enter again. This ensures the atomic operability of the printing process.
In Linux, the key-section locking method is to use pthread_mutex_t for operations, respectively calling pthread_mutex_init, creating and releasing pthread_mutex variables, and calling pthread_mutex_lock and pthread_mutex_unlock for locking and unlocking. Pthread_mutex_init and pthread_mutex_destroy are called once at the beginning and when they are not used. pthread_mutex_lock and pthread_mutex_unlock are called each time the locks and locks are applied. Note that they must be called one by one.
In this example, the mutex is encapsulated using the C ++ construction and analysis structure and template features to ensure that the allocation and release, lock, and unlock are paired, this makes the use of mutex easier. When locking, you only need one statement: auto_guard (Gd, mutex_type, g_gp); this statement is a macro, and the code obtained from expanding the macro is: cautoguard <mutex_type> Gd (g_ctx ); the constructor and destructor of the cautoguard object automatically call the lock and unlock functions of g_ctx to unlock the lock. The lock type depends on mutex_type. The following two rows define the mutex lock type:
Typedef threadmutex mutex_type; // use the mutex type of thread mutex
// Typedef nullmutex mutex_type; // mutex type without mutex
The type of row 1st is threadmutex. We can see the definition of struct. In the lock and unlock functions, pthread_mutex_lock and pthread_mutex_unlock are called respectively, so that the resource is locked and unlocked.
The type of row 2nd is nullmutex. In the definition of struct, the lock and unlock functions are empty functions and no lock and unlock operations are performed.
Therefore, changing the mutex_type type to threadmutex or nullmutex can achieve the effect of using or not using mutex.
Save and compile the above two files:G ++ tmutex. h test. cpp-lpthread-o Test
Compile the output test executable file. Input./TestExecute the program. The following is the execution result of using mutex and not using mutex:
Use mutex:
[Root @ hjclinux sampthread] # G ++ tmutex. h test. cpp-lpthread-o Test
[Root @ hjclinux sampthread] #./test
1
1
1
1
1
1
1
1
1
1
2
2
2
2
2
2
2
2
2
2
Change mutex_type definition in test. cpp to typedef nullmutex mutex_type and then compile the execution result as follows:
[Root @ hjclinux sampthread] #./test
1
2
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
Due to the thread scheduling relationship, the order of printing 1 and 2 may be different each time.