Linux -- ConditionVariable (condition variable) implements producer-consumer model and read/write lock

Source: Internet
Author: User
In the thread synchronization process, there are also the following situations: Thread A needs to wait for A condition to be established before it can continue to run. if the condition is not true, thread A will be blocked, when thread B sets this condition during execution, thread A is awakened to continue execution. In the Pthread Library, use the condition variable to block waiting for a condition, or wake up the thread waiting for this condition. Condition variables are expressed by pthread_cond_t variables. I. condition variables
In the thread synchronization process, there are also the following situations: Thread A needs to wait for A condition to be established before it can continue to run. if the condition is not true, thread A will be blocked, when thread B sets this condition during execution, thread A is awakened to continue execution. In the Pthread Library, use the condition variable to block waiting for a condition, or wake up the thread waiting for this condition. Condition variables are expressed by pthread_cond_t variables.

Use pthread_cond_init to initialize the condition variable. if the condition variable is statically allocated, you can also use a macro to define PTHEAD_COND_INITIALIZER for initialization. use pthread_cond_destroy to destroy the condition variable. if the condition variable is successfully returned, 0 is returned.
A condition variable is always used with a Mutex. A thread can call pthread_cond_wait to block the wait on a condition variable. this function performs the following three steps:
1. release Mutex
2. blocking wait
3. when awakened, obtain Mutex again and return
One thread can call pthread_cond_signal to wake up another thread waiting on a condition variable, or call pthread_cond_broadcast to wake up all threads waiting on this condition variable.
II. use the producer-consumer model to describe
As the name suggests, we can see that to implement this model, there must first be two roles (producers and consumers ), in addition to two roles, of course, there should be an occasion for both critical resources (one occasion) that can be accessed, and the relationship (mutex) between the producer and the producer must be understood ), the relationship between the consumer and the consumer (mutex), the relationship between the producer and the consumer (synchronization and mutex), in general, is a place, two roles, three relationships. It is implemented by code. the producer produces a data, and then sends a signal for the consumer to consume the data. after the consumer consumes the data, it sends a signal to the producer to tell the producer to continue production.

1 # include
 
  
2 # include
  
   
3 # include
   
    
4 # include
    
     
5 # include
     
      
6 typedef int Data_type; 7 typedef int * Data_type_p; 8 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // initialize mutex lock 9 static pthread_cond_t needProduct = PTHREAD_COND_INITIALIZER; // initialize the condition variable 10 11 12 typedef struct listnode // define a linked list to store data (a place) 13 {14 Data_type data; 15 struct listnode * next; 16} list, * listp, ** listpp; 17 18 listp head = NULL; 19 20 static listp buyNode (Data_type _ data) 21 {22 listp tem = (listp) malloc (sizeof (list); 23 if (tem) 24 {25 tem-> data = _ data; 26 tem-> next = NULL; 27 return tem; 28} 29 return NULL; 30} 31 void initList (listpp list) 32 {33 * list = buyNode (0); 34} 35 void push_list (listp list, Data_type _ data) 36 {37 listp cur = buyNode (_ data); 38 listp tem = list; 39 while (tem-> next) 40 {41 tem = tem-> next; 42} 43 tem-> next = cur; 44} 45 void deleteList (listp list) 46 {47 if (list) 48 {49 free (list); 50 list = NULL; 51} 52} 53 int pop_list (listp list, Data_type_p data) 54 {55 if (list-> next = NULL) 56 {57 * data =-1; 58 return-1; 59} 60 listp tem = list-> next; 61 list-> next = tem-> next; 62 * data = tem-> data; 63 deleteList (tem); 64 return 0; 65} 66 void PrintList (listp list) 67 {68 listp cur = list-> next; 69 while (cur) 70 {71 printf ("% d", cur-> data); 72 fflush (stdout); 73 cur = cur-> next; 74} 75 printf ("\ n"); 76} 77 void * product (void * arg) // define the relationship between the producer and the producer (mutually exclusive) 78 {79 int I = 0; 80 while (1) 81 {82 pthread_mutex_lock (& lock); 83 printf ("product data: % d \ n", I ); 84 push_list (head, I ++); 85 pthread_mutex_unlock (& lock); 86 printf ("conducting is OK. weak up comsumer... \ n "); 87 pthread_cond_signal (& needProduct); // when the producer has data, send a signal to wake up the consumer 88 sleep (2 ); 89} 90 91} 92 void * consumer (void * arg) // The relationship between the consumer and the consumer (mutually exclusive) 93 {94 Data_type _ data; 95 while (1) 96 {97 pthread_mutex_lock (& lock); 98 while (-1 = pop_list (head, & _ data) 99 {100 pthread_cond_wait (& needProduct, & lock ); // wait until 101} 102 printf ("consumer data: % d \ n", _ data); 103 pthread_mutex_unlock (& lock ); 104 sleep (1); 105} 106} 107 int main () 108 {109 initList (& head); 110 pthread_t id1; 111 pthread_t id2; 112 pthread_create (& id1, NULL, product, NULL); 113 pthread_create (& id2, NULL, consumer, NULL); 114 pthread_join (id1, NULL); 115 pthread_join (id2, NULL); 116 return 0; 117}
     
    
   
  
 

Conclusion: The above code implements a single producer and single consumer, producer-consumer model. Simply put, it is necessary to achieve mutual exclusion between producers and consumers, and mutual exclusion between consumers and consumers, the producer and consumer are mutually exclusive.

3. use semaphores to implement the producer-consumer model
The Mutex variable is a non-zero value (1) and can be considered as the number of available resources. the Mutex variable is 1 during initialization, indicating that there is a available resource,
When the lock is applied, the resource is obtained and Mutex is reduced to 0, indicating that no available resources are available. when the resource is unlocked, the Mutex is released and added to 1 again, indicating that another available resource is available. Similar to Mutex, Semaphore indicates the number of available resources. Unlike Mutex, this number can be greater than 1. That is, if the number of resources described by the semaphore is 1, the semaphore is the same as the mutex lock!
Sem_init () initialize the Semaphore

Sem_wait () P operation to obtain resources

Sem_post () V action to release resources

Sem_destroy () destroy semaphores

The above is the producer-consumer model written with a linked list. its space is dynamically allocated. now, the producer-consumer model is rewritten based on a fixed-size annular queue.

1 # include
 
  
2 # include
  
   
3 # include
   
    
4 # define PRODUCT_SIZE 20 5 # define CONSUMER_SIZE 0 6 7 sem_t produceSem; 8 sem_t consumerSem; 9 int Blank [PRODUCT_SIZE]; 10 11 void * product (void * arg) 12 {13 int p = 0; 14 while (1) 15 {16 sem_wait (& produceSem); // Apply for resources. 17 int _ product = rand () % 100; 18 Blank [p] = _ product; 19 printf ("product is OK, value is: % d \ n ", _ product); 20 sem_post (& consumerSem); // release resource 21 p = (p + 1) % PRODUCT_SIZE; 22 sleep (rand () % 3 ); 23} 24 25} 26 void * consumer (void * arg) 27 {28 int p = 0; 29 while (1) 30 {31 sem_wait (& consumerSem ); // Request resource 32 int _ consumer = Blank [p]; 33 printf ("consumer is OK, value is: % d \ n", _ consumer ); 34 sem_post (& produceSem); // release resource 35 p = (p + 1) % PRODUCT_SIZE; 36 sleep (rand () % 5 ); 37} 38} 39 int main () 40 {sem_init (& produceSem, 0, PRODUCT_SIZE); 41 sem_init (& consumerSem, 0, CONSUMER_SIZE); 42 pthread_t tid1, tid2; 43 pthread_create (& tid1, NULL, product, NULL); 44 pthread_create (& tid2, NULL, consumer, NULL); 45 pthread_join (tid1, NULL); 46 pthread_join (tid2, NULL); 47 sem_destroy (& produceSem); 48 sem_destroy (& consumerSem); 49 return 0; 50}
   
  
 

IV. read/write locks
The read/write lock is actually a special spin lock used to deal with the case of reading more and writing less, it divides the visitors to the shared resources into readers and writers, the reader only reads and accesses shared resources, and the writer needs to write the shared resources. Compared with the spin lock, this lock can improve concurrency because in a multi-processor system, it allows multiple readers to access shared resources at the same time, the maximum number of possible readers is the actual number of logical CPUs. The writer is exclusive. a read/write lock can only have one or more writers (related to the number of CPUs), but not both readers and writers. Read/Write locks also follow three relationships: reader-writer (mutex and synchronization), reader-reader (irrelevant), and writer-writer (mutex ), 1 place.
Pthread_rwlock_wrlock write method, 0 is returned for success, and error code is returned for failure

Pthread_rwlock_rdlock: read mode. if the Read succeeds, 0 is returned. if the read operation fails, an error code is returned.

Pthread_rwlock_init initialization

1 # include
 
  
2 # include
  
   
3 # define _ READNUM _ 2 4 # define _ WREITENUM _ 3 5 pthread_rwlock_t lock; 6 int buf = 0; 7 void * read (void * reg) 8 {9 while (1) 10 {11 if (pthread_rwlock_tryrdlock (& lock )! = 0) // Read mode 12 {13 printf ("writer is write! Reader wait... \ n "); 14} 15 else 16 {17 printf (" reader is reading, val is % d \ n ", buf); 18 pthread_rwlock_unlock (& lock ); 19} 20 sleep (2); 21} 22} 23 void * write (void * reg) 24 {25 while (1) 26 {27 if (pthread_rwlock_trywrlock (& lock )! = 0) // write mode 28 {29 printf ("reader is reading! Writer wait... \ n "); 30 sleep (1); 31} 32 else 33 {34 buf ++; 35 printf (" writer is writing, val is % d \ n ", buf); 36 pthread_rwlock_unlock (& lock); 37 38} 39 sleep (1); 40} 41} 42 int main () 43 {44 pthread_rwlock_init (& lock, NULL ); 45 pthread_t tid; 46 int I = 0; 47 for (I; I <_ WREITENUM _; I ++) 48 {49 pthread_create (& tid, NULL, write, NULL ); 50} 51 52 for (I; I <_ READNUM _; I ++) 53 {54 pthread_create (& tid, NULL, read, NULL); 55} 56 pthread_join (tid, NULL); 57 sleep (100); 58 return 0; 59}
  
 

The above is the content for implementing the producer-consumer model and read/write locks in Linux -- Condition Variable (Condition Variable). For more information, see PHP Chinese network (www.php1.cn )!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.