Home PC Games Linux Windows Database Network Programming Server Mobile  
           
  Home \ Programming \ Simple to use multi-threaded programming under Linux mutex and condition variable     - Configuring Allatori code confusion when developing general Java applications in NetBeans (Programming)

- Docker build private warehouse (Server)

- Shell script on the variables with double quotation marks grep small problem (Programming)

- Elasticsearch 2.20 Highlight (Server)

- Try debugfs restore the deleted files ext3 file system (Linux)

- Python Django direct implementation of sql statement (Programming)

- Understanding and Memcached MongoDB arbitration node, Zookeeper, Redis Recovery Programme Thoughts (Database)

- Iptables application layer plug (Linux)

- Linux System Getting Started Learning: the curl set custom HTTP header (Linux)

- Efficient Linux Shell - Shell special characters Summary (Linux)

- Configuring automatic mail GAMIT under CentOS system (Linux)

- REDO LOG records management (Database)

- RHEL6.4 one key installation Redmine (Linux)

- After VMware CentOS full VM clone the network card is unavailable Solutions (Linux)

- Python closure and function objects (Programming)

- Ubuntu Linux use MAC binding against ARP attacks (Linux)

- LinkedList Basic Usage (Programming)

- Linux shell script under the use of randomly generated passwords (Programming)

- Install the Red Hat Container Development Kit on OSX (Server)

- FFmpeg compiled with only H264 decoding library (Programming)

 
         
  Simple to use multi-threaded programming under Linux mutex and condition variable
     
  Add Date : 2017-01-08      
         
         
         
  Under multithreaded Linux follows the POSIX thread interface called pthread. Write multi-threaded programs under Linux, you need to use the header files pthread.h, need to use the library libpthread.a link. A thread is a physical process, is the basic unit of CPU scheduling and dispatching, which is smaller than the basic unit of the process can operate independently. All threads own resources have essentially no system resources, has only a little in the operation of essential resources (such as the program counter, a set of registers and stack), but it may have with other threads share the process belong to a process of . When multiple tasks can be executed in parallel, you can start a thread for each task.

Threads are running concurrently. Introduced in the serial program threads and processes on the basis of the program is to provide the degree of concurrency, thereby improving program efficiency and response time.

Compared with the process, thread advantages:
(1), threads share the same memory space, different threads can access the same memory in a variable;
(2), with a standard fork () compared to the thread overhead is small, saving CPU time, making thread creation ten to one to create a hundred times faster than the new process.


Adapt multithreading reasons:
1), And compared to the process, it is a very "frugal" multitasking operating mode in Linux system, start a new process must be assigned to it a separate address space, the establishment of a large number of data tables to maintain its code segment, stack and data segments, which is an "expensive" for multitasking work. The process of running a plurality of threads between each other using the same address space, most of the data sharing, start a thread spends far less than the space it takes to start a process space, and, switching between threads required for each other the time is far less than the process of switching between the time required;
(2), To facilitate inter-thread communication mechanisms. For different processes, they have separate data space, data transfer can only be carried out by means of communication, this approach is not only time-consuming and inconvenient. Otherwise the thread is shared between threads of the same process under the data space, so a thread data can be used directly by other threads, it is not only fast, but also convenient.


Multi-threaded program as a multi-tasking, concurrent work, its advantages include: (1) to provide application response; (2) to make multi-CPU system more efficient: the operating system will ensure that when the thread count is not greater than the number of CPU time , different threads running on different CPU; (3), to improve the program structure: a long and complex process can be considered divided into multiple threads into several independent or semi-independent part of the run, such a program in favor of understanding and modifications.

pthread_create: used to create a new thread in the calling process. It has four parameters, the first parameter is a pointer to point to the thread identifier; The second parameter is used to set thread attributes; the third parameter is the starting address of the thread running function; The fourth parameter is a function of operating parameters.

After creating a new thread calls the pthread_create function in a thread, the current thread to continue down from pthread_create place. The third parameter pthread_create function to create the starting address for the new thread's entry function, this function takes one argument, by the fourth parameter passed to it, the type of the parameter is void *, the pointer on what type of interpretation defined by the caller himself, return value type entry function is void *, the meaning of pointers same caller own definition, entry function returns, the thread exits, the other thread can call pthread_join function to get the entry function's return value .

pthread_join: thread blocking function for blocking the current thread until another end of a thread running; make a thread wait for the end of another thread; blocking the main thread in this place waiting for child thread ends; if there is no code will be the main thread pthread_join Near the end of the end so that the entire process, so that the thread does not create the opportunity to begin execution is over, after adding pthread_join, the main thread will wait until the end of the thread to wait until the end of themselves, so that the thread has created the opportunity to perform.

pthread_create a thread split into two, pthread_join () will merge two threads into one thread.

A thread is actually a function, after you create, be executed immediately, when the function returns the thread will be over.

When the thread terminates, a need to take care of is synchronization between threads. Under normal circumstances, the process of running the various threads are independent and do not terminate the thread and inform each other, it will not affect other threads, the thread terminated resources occupied by the thread will not end with the termination and return system, is still holding for the process thread is located. A thread allows only one thread uses pthread_join to wait for its termination, and are waiting to join thread should be in the state, rather than the DETACHED state. A "join" the memory occupied by threads only when there is a thread on its implementation of pthread_join () until after the release, so in order to avoid memory leaks, all threads to terminate, or to DETACHED, or use pthread_join to recover resources. A thread can not be more than one thread to wait.

All threads have a thread number, which is threadid, of type pthread_t, can be obtained by calling the function pthread_self own thread number.

Several basic ways Linux thread synchronization: join, mutex (mutex), read-write lock (read-writelock), condition variables (condition variables). Nature mutex is locked, and the nature of the condition variable is waiting.

Mutually exclusive: This simply means that, after a thread into the work area, if there are other threads that want to enter the work area, it will enter the wait state, you can enter after the end of the thread to wait for the work area.

Mutual exclusion between threads to provide exclusive access to resources controlled. It is a simple lock, only the thread that holds it can release the mutex. It ensures the integrity they are accessing shared resources, because at the same time allowing only one thread to access it.

Mutual exclusion, that is a piece of code or modify a variable when only one thread executing this code, other threads can not enter the code or modify the variables at the same time. This code or variable called critical resources.

Synchronize threads through the same time locking mechanism allowing only one thread is executing a critical section of code.

There are two ways to create a mutex, static and dynamic way.

By default, the same thread in Linux will not be the same recursive mutex lock, a deadlock would otherwise occur. The so-called recursive lock, is an attempt to be more than twice the mutex behavior or twice in the same thread. Solution to the problem is to be displayed when the mutex variable is initialized to set recursive property.

Mutex is a multithreaded method for synchronous access, which allows the program to lock an object or a piece of code, so you can only have one thread to access it. In order to control access to critical objects or code, you must lock a mutex before entering the code, and then after the completion of the operation unlock.

Mutex with pthread_mutex_t data types to represent, before using the mutex variable, you must first initialize it, it can be set to a constant PTHREAD_MUTEX_INITIALIZER (mutex only for statically allocated), can also be initialized by calling the function pthread_mutex_init . If the dynamic allocation of the mutex (such as calling malloc) function, then free the memory before the (free) is required pthread_mutex_destroy function.

Access to shared resources, we should be on the mutex lock, if the mutex is already locked, the calling thread blocks until the mutex is unlocked. After the completion of the access to shared resources, and to unlock the mutex.

pthread_mutex_init function: mainly used for multithreading mutex initialization. If you use the default initialization mutex attributes, just the second parameter set to NULL. Mutex attributes can be divided into four categories: (1), PTHREAD_MUTEX_TIMED_NP, which is the default, which is the ordinary locks When a thread lock, the lock thread remaining requests will form a queue and unlock priority to acquire a lock, this lock strategy to ensure the equitable distribution of resources; (2), PTHREAD_MUTEX_RECURSIVE_NP, nested lock allows multiple threads lock, different threads, re-unlock competition; (3), PTHREAD_MUTEX_ERRORCHECK_NP, seizure wrong, if the mutex is already locked, then the subsequent lock will fail without blocking, otherwise the PTHREAD_MUTEX_TIMED_NP same type, so it does not get repeated when locking is not allowed in the simplest case deadlock; (4), PTHREAD_MUTEX_ADAPTIVE_NP, adapt lock, action lock the easiest type of competition only to wait again after unlocking.

pthread_mutex_destroy function: destruction (cancellation) thread mutex; destroy a mutex release means that it takes up resources, and requires lock is currently open.

pthread_mutex_lock: possession of mutex (blocking operation); mutex is locked, if the mutex locked and owned by a thread, then another thread to call this function will enter the blocked state (ie wait state) until mutual mutex is released; once after the mutex locked by other threads if you want to lock the mutex, it will clog in this operation, if before the mutex is already locked by other threads , then the operation will have been blocked in this place, until the lock.

pthread_mutex_unlock: release the mutex; after the operation is complete, you must call this function to unlock the mutex so that other threads have a chance to wait for the lock to get the lock, or the other thread will block forever.

With different mutex, condition variables are used rather than to wait for locked. Condition variable used to automatically block a thread until a special occasion occurs. Typically condition variables and mutex simultaneously. Condition variables are divided into two parts: the conditions and variables. Condition itself is protected by a mutex. Thread state before changing the conditions must first lock mutex. Condition variables so that we can sleep waiting for some condition to occur. Condition variable shared among threads is the use of global variables in a mechanism for synchronizing, including two actions: a thread to wait for "condition variable conditions set up a" hang; another thread so that the "condition is satisfied" (given condition is satisfied signal). Test conditions under the protection of a mutex. If a condition is false, a thread is blocked, and release the mutex wait state change. If another thread changes the condition, it sends a signal to the associated condition variable, wake up one or more threads wait for it to regain mutex, re-evaluation criteria. If two threads share a readable and writable memory, condition variables can be used to implement thread synchronization between these two threads.

Mutex is a clear disadvantage is that it has only two states, locking and non-locking. The condition variable by allowing the thread to block and wait for another thread sends a signal to make up for the lack of a method mutex, and it is often used in conjunction with a mutex. When used, the condition variable is used to block a thread, when the conditions are not met, often unlock the corresponding thread mutex and wait for conditions to change. Once a change in the other thread condition variable, it will notify the appropriate one or more wake-up condition variable being blocked this condition variable thread. These threads will re-lock the mutex and re-test conditions are met. In general, the condition variable is used to synchronize threads. Condition variables and just play the role of blocking threads are awakened, the specific determination condition given by the user needs. After the thread wakes up, it will re-examination to determine whether the conditions are met, if not satisfied, in general, should still be blocked thread here, it is waiting to be the next wake. This process is generally implemented by the while statement.

Condition variables pthread_cond_t structure to represent.

pthread_cond_init: initialize a condition variable, the second argument when the property is a null pointer, the function creates a default condition variable, otherwise the property will be the second condition variable attribute values of the parameters to decide. You can not initialize a condition variable by multiple threads. When you need to re-initialize or release a condition variable, the application must ensure that this condition variable is not in use.

pthread_cond_wait: blocked on the condition variable, function parameter points to unlock the second mutex and the current thread is blocked on the condition variable pointed to by the first argument. Blocked thread can be pthread_cond_signal, pthread_cond_broadcast wake-up function, it may also be interrupted in the wake-up signal after.

Usually a conditional expression is under the protection of a mutex is checked. When the conditional expression is not satisfied, the thread will remain blocked on the condition variable. When another thread changes the value of the variable conditions to conditions signaled when waiting on this condition variable of a thread or all threads are awakened, then they tried to occupy the corresponding mutex again. After being awakened, until pthread_cond_wait function returns, the value of the condition are likely to vary blocked threads on the condition variable. So after the function returns, before locking the corresponding mutex, conditions must be re-tested values. The best test is to cycle call pthread_cond_wait function, and to meet the conditions set for the expression termination condition for the loop. Blocked on a condition variable of the same order of different threads is not necessarily to be released.

pthread_cond_wait function is the exit point, if this function is called, has a pending withdrawal request and allow the thread exits, the thread will be terminated and started dealing with the aftermath function, but this time and condition variables associated mutex It will remain in the locked state.

pthread_cond_signal: unblock the condition variable. This function is used to release blocked on the specified condition variable of a thread. Usually used in protection of a mutex corresponding condition variable, otherwise unlocked condition variable may occur before locking condition variable, resulting in a deadlock. Wake blocked on the condition variable is determined by the order of all the threads scheduling policy.

pthread_cond_timewait: blocks until the specified time. Function to a certain time, even if the condition does not occur is unblocked. The time is specified by the third argument.

pthread_cond_broadcast: release all the threads blocked. Function wakes up all pthread_cond_wait function blocks on a condition variable thread. When no threads are blocked on the condition variable, this function is invalid. This function wakes up all blocked on a condition variable thread, these threads will be awakened competition corresponding mutex again.

pthread_cond_destroy: release condition variable. Condition variable space occupied is not released.

pthread_cond_wait pthread_cond_timewait and must be used within the mutex lock region; and pthread_cond_signal and pthread_cond_broadcoast regardless of whether the calling thread is the owner of the mutex, you can call the area outside of the lock and unlock.

A particular condition can have a mutex, and condition variable should be mutually exclusive data shows an "inside" special conditions change. A mutex variable can have many conditions, but each condition variable can have a mutex object.

Return all of the above thread-related function, the function is executed successfully 0 0 Other non-return value indicates an error.

Here are some examples of tests:

1. test_create_thread.cpp:

#include < pthread.h>
#include < iostream>
#include < unistd.h>

using namespace std;

void * run (void * para)
{
 cout << "start new thread!" << endl;
 
 // Sleep (5); // suspend 5 s, in a formal code, generally do not use sleep function
 int * iptr = (int *) ((void **) para) [0];
 float * fptr = (float *) ((void **) para) [1];
 char * str = (char *) ((void **) para) [2];
 cout << * iptr << "" << * fptr << "" << str << endl;

 cout << "end new thread!" << endl;
 
 return ((void *) 0);
}

int main ()
{
 pthread_t pid; // thread handle
 int err = -1;
 int ival = 1;
 float fval = 10.0F;
 char buf [] = "func";
 void * para [3] = {& ival, & fval, buf};

 err = pthread_create (& pid, NULL, run, para);
 if (err! = 0) {
  cout << "can not create thread!" << endl;
  return -1;
 }

 // Create a new thread after thread runs ---- how to master the main thread in order to continue to the next line program
 cout << "main thread!" << endl;
 
 // How at the end of the new thread ---- new thread to stop, and then as part of its cleanup process, waiting for merged with another thread, or "connections"
 pthread_join (pid, NULL);

 cout << "ok!" << endl;

 return 0;
}

// Terminal performs: $ g ++ -o test_create_thread test_create_thread.cpp -lpthread
// $ ./test_create_thread

2. test_thread_mutex.cpp:

#include < pthread.h>
#include < iostream>

using namespace std;

pthread_t tid [2];
int counter = 0;
pthread_mutex_t lock;

void * run (void * arg)
{
 pthread_mutex_lock (& lock);

 unsigned long i = 0;
 counter + = 1;
 cout << "Job" << counter << "started!" << endl;
 for (i = 0; i <(0xFFFFFFFF); i ++);
 cout << "Job" << counter << "finished!" << endl;

 pthread_mutex_unlock (& lock);

 return NULL;
}

int main ()
{
 int i = 0, err = -1;

 if (pthread_mutex_init (& lock, NULL)! = 0) {
  cout << "mutex init failed" << endl;
  return -1;
 }

 while (i < 2) {
  err = pthread_create (& (tid [i]), NULL, & run, NULL);
  if (err! = 0)
   cout << "can not create thread!" << endl;
  i ++;
 }

 pthread_join (tid [0], NULL);
 pthread_join (tid [1], NULL);
 pthread_mutex_destroy (& lock);

 cout << "ok!" << endl;
 return 0;
}

// Terminal performs: $ g ++ -o test_thread_mutex test_thread_mutex.cpp -lpthread
// $ ./test_thread_mutex

3. test_thread_cond.cpp:

#include < pthread.h>
#include < iostream>
#include < unistd.h>

using namespace std;

pthread_mutex_t count_lock;
pthread_cond_t count_nonzero;
unsigned count = 0;

void * decrement_count (void * arg)
{
 pthread_mutex_lock (& count_lock);
 cout << "decrement_count get count_lock" << endl;

 while (count == 0) {
  cout << "decrement_count count == 0" << endl;

  cout << "decrement_count before cond_wait" << endl;
  pthread_cond_wait (& count_nonzero, & count_lock);
  cout << "decrement_count after cond_wait" << endl;
 }

 count = count + 1;

 pthread_mutex_unlock (& count_lock);

 return NULL;
}

void * increment_count (void * arg)
{
 pthread_mutex_lock (& count_lock);
 cout << "increment_count get count_lock" << endl;

 if (count == 0) {
  cout << "increment_count before cond_signal" << endl;
  pthread_cond_signal (& count_nonzero);
  cout << "increment_count after cond_signal" << endl;
 }

 count = count + 1;

 pthread_mutex_unlock (& count_lock);

 return NULL;
}

int main ()
{
 pthread_t tid1, tid2;

 pthread_mutex_init (& count_lock, NULL);
 pthread_cond_init (& count_nonzero, NULL);

 pthread_create (& tid1, NULL, decrement_count, NULL);
 sleep (2);

 pthread_create (& tid2, NULL, increment_count, NULL);
 sleep (2);

 pthread_join (tid1, NULL);
 pthread_join (tid2, NULL);
 pthread_mutex_destroy (& count_lock);
 pthread_cond_destroy (& count_nonzero);

 cout << "ok!" << endl;
}

// Terminal performs: $ g ++ -o test_thread_cond test_thread_cond.cpp -lpthread
// $ ./test_thread_cond

4. test_thread_cond1.cpp:

#include < pthread.h>
#include < iostream>
#include < unistd.h>

using namespace std;

pthread_mutex_t counter_lock;
pthread_cond_t counter_nonzero;
int counter = 0;

void * decrement_counter (void * argv);
void * increment_counter (void * argv);

int main ()
{
 cout << "counter:" << counter << endl;
 pthread_mutex_init (& counter_lock, NULL);
 pthread_cond_init (& counter_nonzero, NULL);

 pthread_t thd1, thd2;
 int ret = -1;

 ret = pthread_create (& thd1, NULL, decrement_counter, NULL);
 if (ret) {
  cout << "create thread1 fail" << endl;
  return -1;
 }

 ret = pthread_create (& thd2, NULL, increment_counter, NULL);
 if (ret) {
  cout << "create thread2 fail" << endl;
  return -1;
 }

 int counter = 0;
 while (counter! = 10) {
  cout << "counter (main):" << counter << endl;
  sleep (1);
  counter ++;
 }

 pthread_join (thd1, NULL);
 pthread_join (thd2, NULL);
 pthread_mutex_destroy (& counter_lock);
 pthread_cond_destroy (& counter_nonzero);

 cout << "ok!" << endl;
}

void * decrement_counter (void * argv)
{
 cout << "counter (decrement):" << counter << endl;

 pthread_mutex_lock (& counter_lock);
 while (counter == 0)
  pthread_cond_wait (& counter_nonzero, & counter_lock); // enter blocked (wait), awaiting activation (signal)

 cout << "counter - (decrement, before):" << counter << endl;
 counter--; // wait signal activated after execution
 cout << "counter - (decrement, after):" << counter << endl;
 pthread_mutex_unlock (& counter_lock);

 return NULL;
}

void * increment_counter (void * argv)
{
 cout << "counter (increment):" << counter << endl;

 pthread_mutex_lock (& counter_lock);
 if (counter == 0)
  pthread_cond_signal (& counter_nonzero); // activation (signal) blocked (wait) thread (first thread executing the signal, then execution wait thread)

 cout << "counter ++ (increment, before):" << counter << endl;
 counter ++;
 cout << "counter ++ (increment, after):" << counter << endl;
 pthread_mutex_unlock (& counter_lock);

 return NULL;
}

// Terminal performs: $ g ++ -o test_thread_cond1 test_thread_cond1.cpp -lpthread
// $ ./test_thread_cond1

5. test_thread_cond2.cpp:

#include < pthread.h>
#include < iostream>
#include < unistd.h>

using namespace std;

pthread_mutex_t counter_lock1, counter_lock2;
pthread_cond_t counter_nonzero1, counter_nonzero2;
int counter = 0;

void * decrement_increment_counter (void * argv);

int main ()
{
 cout << "counter:" << counter << endl;
 pthread_mutex_init (& counter_lock1, NULL);
 pthread_mutex_init (& counter_lock2, NULL);
 pthread_cond_init (& counter_nonzero1, NULL);
 pthread_cond_init (& counter_nonzero2, NULL);

 pthread_t thd;
 int ret = -1;

 ret = pthread_create (& thd, NULL, decrement_increment_counter, NULL);
 if (ret) {
  cout << "create thread1 fail" << endl;
  return -1;
 }

 int counter = 0;
 while (counter! = 10) {
  cout << "counter (main):" << counter << endl;
  sleep (1);
  counter ++;
 }

 pthread_join (thd, NULL);
 pthread_mutex_destroy (& counter_lock1);
 pthread_mutex_destroy (& counter_lock2);
 pthread_cond_destroy (& counter_nonzero1);
 pthread_cond_destroy (& counter_nonzero2);

 cout << "ok!" << endl;
}

void * decrement_increment_counter (void * argv)
{
 cout << "start counter:" << counter << endl;

 pthread_mutex_lock (& counter_lock1);
 cout << "counter (decrement):" << counter << endl;
 while (counter == 1)
  pthread_cond_wait (& counter_nonzero1, & counter_lock1); // enter blocked (wait), awaiting activation (signal)

 cout << "counter - (decrement, before):" << counter << endl;
 counter--; // wait signal activated after execution
 cout << "counter - (decrement, after):" << counter << endl;
 pthread_mutex_unlock (& counter_lock1);

 pthread_mutex_lock (& counter_lock2);
 cout << "counter (increment):" << counter << endl;
 if (counter == 0)
  pthread_cond_signal (& counter_nonzero2); // activation (signal) blocked (wait) thread (first thread executing the signal, then execution wait thread)

 cout << "counter ++ (increment, before):" << counter << endl;
 counter ++;
 cout << "counter ++ (increment, after):" << counter << endl;
 pthread_mutex_unlock (& counter_lock2);

 return NULL;
}

// Terminal performs: $ g ++ -o test_thread_cond2 test_thread_cond2.cpp -lpthread
// $ ./test_thread_cond2
     
         
         
         
  More:      
 
- Experience CoreCLR stack unwinding characteristics of initial implementation on Linux / Mac (Linux)
- CentOS 7 x64 compiler installation Tengine 2.0.3 Comments (Server)
- The Java development environment to build under Ubuntu 14.04 (Linux)
- Cacti Linux-based system monitoring and alarm (Linux)
- cursor_sharing induced error ORA-00600 (Database)
- [Android] Eclipse does not update the Android SDK Manager solution [using GoAgent] (Programming)
- Quick paging ROW_NUMBER conducted (Database)
- Ubuntu 14.10 PPA installed Android Studio (Linux)
- apt-get install openstack pkg Troubleshooting (Linux)
- Teach you how to protect the Linux operating system security tips (Linux)
- Vagrant Getting Start (Linux)
- Installation and Configuration Munin monitoring server on Linux (Server)
- CentOS6.0 successful installation and configuration OpenCV (Linux)
- Linux more efficient than select a model epoll (Linux)
- CentOS 6 / Linux su: Unable to set user ID: Resource temporarily unavailable (Linux)
- Puppet 3.5 Source package Installation and Configuration (Server)
- MD5 and simple to use (Linux)
- Safety testing Unix and Linux server entry succinctly (Linux)
- Ubuntu Thunderbird 24.4.0 (Linux)
- Comparison of Nginx and Nginx + (Server)
     
           
     
  CopyRight 2002-2022 newfreesoft.com, All Rights Reserved.