Non-real read/write locks, non-real read/write locks

Source: Internet
Author: User
Tags usleep

Non-real read/write locks, non-real read/write locks

There is a single write thread and multiple read threads are concurrently used. For example, when reading and updating measurement data, there are many consumers and there is only one producer. Example:

The left side is a classic solution that locks the entire data operation. It is a waste of time to lock all read threads for a Data Writing thread. Therefore, the Reader/Writer Lock is proposed. Even if a read/write Lock is used, its essence is the same, and the internal implementation of pthread under POSIX is based on mutex, therefore, it has higher overhead. If there is no heavy read operation to offset the overhead it introduces, it will lead to performance degradation. Multiple groups of test data have been used to prove this. I did the verification myself and got the following data (a single write thread, 20 read threads). Using the read/write lock is slower than using mutex. For details, refer to the two links:
* Mutex or Reader Writer Lock
* Multi-threaded programming: efficiency of locking

This type of problem has a type of solution in the database field, called Multiversion Concurrency Control, which aims to add data copies to ensure that users can use complete data every time they use it, but not necessarily the latest data. To simplify it, the idea is to create a copy of data for writing. When the data is fully prepared, it is switched out for other threads to read. The original data is converted to the next write operation. That is, the method shown on the right.
In this solution, you only need to lock the processing of Writing/Reading. In this way, the performance overhead is tested because the Lock processing time is very short, which is better than Mutex and Reader/Writer Lock (the last algorithm ):

The details are not expanded. In addition, there are some more common methods called Spin Buffer, which can be further studied if you are interested.

The source code is as follows:

#include <pthread.h>#include <iostream>#include <stdio.h>#include <unistd.h>#include <ctime>// #define USE_MUTEX// #define USE_RW_LOCK// X + Y = 0typedef struct _Data{  int x;  int y;} Data;namespace {  Data globalData[2] = {{1,-1}, {1,-1}};  int WriteIndex = 0;  int ReadingIndex = 1;  float globalReadingTimeCost = 0.0f;#ifdef USE_MUTEX  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;#endif#ifdef USE_RW_LOCK  pthread_rwlock_t rwlock;#endif  const int thread_number = 20;}void* write_thread(void* param) {  clock_t begin_time = std::clock();  for(int i=1; i<=1000; i++) {    globalData[WriteIndex].x = i;    globalData[WriteIndex].y = -1 * i;    usleep(1);#ifdef USE_MUTEX    pthread_mutex_lock(&mutex);#endif#ifdef USE_RW_LOCK    pthread_rwlock_rdlock(&rwlock);#endif    ReadingIndex = WriteIndex;    WriteIndex = (WriteIndex + 1) % 2;#ifdef USE_MUTEX    pthread_mutex_unlock(&mutex);#endif#ifdef USE_RW_LOCK    pthread_rwlock_unlock(&rwlock);#endif    usleep(600);  }  std::cout<< "[Writing Thread]" << float( std::clock () - begin_time ) /  CLOCKS_PER_SEC * 1000 << std::endl;  return NULL;}void* read_thread(void* param) {  clock_t begin_time = std::clock();  for(int i=1; i<=20000; i++) {#ifdef USE_MUTEX    pthread_mutex_lock(&mutex);#endif#ifdef USE_RW_LOCK    pthread_rwlock_wrlock(&rwlock);#endif    int index = ReadingIndex;#ifdef USE_MUTEX    pthread_mutex_unlock(&mutex);#endif#ifdef USE_RW_LOCK    pthread_rwlock_unlock(&rwlock);#endif    int x = globalData[index].x;    int y = globalData[index].y;    if (x + y != 0) {      std::cout << std::endl << "Wrong data:" << x << "," << y << std::endl;    }    usleep(3);  }  std::cout<< "[Reading Thread]" << float( std::clock () - begin_time ) /  CLOCKS_PER_SEC * 1000 << std::endl;  return NULL;}int main(void) {  int ret = 0;  pthread_t id[thread_number];#ifdef USE_RW_LOCK  pthread_rwlock_init(&rwlock, NULL);#endif  clock_t begin_time = std::clock();  // One writing thread  ret = pthread_create(&id[0], NULL, write_thread, NULL);  if (ret) {    std::cout << "Failed to launch writing thread." << std::endl;    return -1;  }  // Four reading threads  for (int i=1; i<thread_number; i++) {    pthread_create(&id[i], NULL, read_thread, NULL);  }  for (int i=0; i<=thread_number; i++) {    pthread_join(id[i], NULL);  }  std::cout<< "Cost:" << float( std::clock () - begin_time ) /  CLOCKS_PER_SEC * 1000 << std::endl;  return 0;}

Compile the test as follows:

g++ -std=c++11 -DUSE_MUTEX thread.cc -lpthread -o thread

If you have time, write another article about multithreading algorithm selection!

Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.

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.