How to Solve Easily the Reader-Writer Locks in Golang


Reader-writer locks are one of the most intriguing topics in Golang. Golang web app development requires extensive use of goroutines and channels, which support concurrency. And this is where locks, or as we will learn reader-writer locks come in handy. 


What is the Concept of Locks in Golang?

  • The notion of locks is not only restricted to Golang, but it can be applied in a plethora of  ing languages. Locks, which prevent access to sensitive data, may cause additional overheads in complex applications. Then it has to be optimized by developers. Reader-writer locks are one of the most popular techniques to optimize it.

  • Developers who are new to the concept of locks use Golang to comprehend the idea. This is because Golang has a great reader-writer lock implementation and concurrency support. 


What is the Requirement of Reader-Writer Locks?

  • As long as no one modifies the shared data while it is being read, several threads can access it concurrently. You should know that reader-writer locks are created in this way. 

  • Any thread reading data will still need to lock it since standard locks don't distinguish between "lock for reading" and "lock for writing," which causes extra serialization.

  • Now, if one must draw a necessary distinction between readers and writers, it results in an unintended distinction between readers. And here's when the RW locks play a pivotal role. They don't rely on just one lock system.


Golang web app development is not easy as it involves a number of factors. If you have a hard time developing a scalable and high-performing web app, then you should take the help of the developers at Golang.Company. 


How to Use Mutexes in Go?

  • In this blog, we will take a look at race situations and how mutexes may be used to avoid them. Due to the difficulty of debugging and fixing problems in new systems, race conditions might result in unforeseen problems.

  • As a result, we will construct a Go program from scratch in this blog that can run simultaneously in a secure way without degrading performance. And this is where the Mutex or Mutual Exclusion is used.


What Do You Mean by Mutex?

Mutex is a mechanism that enables us to stop concurrent processes from accessing a crucial area of code that has already been run by one particular process.


Implementation of Mutex

Reading the Issue:

  • Consider a client who has a $1,000 bank balance. The consumer then tries to credit his account with $500 more. In this instance, a goroutine would observe the transaction, determine that it was worth $1,000, and then continue to deposit $500 into the bank.


  • Imagine that he also has a mortgage payment of $600 to make at the same time. Before the first process can deposit a further $500, the second process will interpret the account's original value as $600.

  • The $600 is then subtracted from the $1,000 after that. When the consumer checks his bank account the next day and discovers that he has $400 left. This is due to the fact that the second process, which had no knowledge of the initial deposit, decided to ignore the value once the second goroutine was finished.

  • Let's try using a mutex to solve the problem now that we are aware of it.


package main

import (
fmt
sync
)

var (
mutex sync.Mutex
amount int
)


func deposit(value int, wg *sync.WaitGroup) {

mutex.Lock()

fmt.Printf(Depositing %d to the account with balance %d\n, value, amount)

amount += value

mutex.Unlock() 

wg.Done() 

}


func extract(value int, wg *sync.WaitGroup) {

mutex.Lock()

fmt.Printf(Withdrawing %d from account with balance %d\n, value, amount)

amount -= value

mutex.Unlock()

wg.Done() 

}


func main() {

fmt.Println(Hello Everyone)

amount=1000

var wg sync.WaitGroup

wg.Add(2)

go extract(600, &wg)

go deposit(500, &wg)

wg.Wait()

fmt.Printf(New Balance %d\n, amount)

}


  • First we define the mutex. You can notice that we have mutex of type sync.Mutex and type int amount. Then, we will initialize the amount in the main function (1000). 

  • I then defined two functions after that. The deposit serves as the first function, while the extract serves as the second.

  • The deposit function accepts parameters: value of type int and a waitgroup, i.e, *sync.WaitGroup. The WaitGroup plays a crucial role in waiting for all of the operating goroutines to complete their tasks.

  • Our aim is to attain the mutex lock highlighted in the var, by calling .Lock() function.

  • Next, we are printing “Depositing %d to the account with balance %d\n”, value, amount. We are passing value and amount as parameters. 

  • We will then carry out the computations, resulting in amount += value.

  • With the help of mutex.Unlock(), we will unlock the mutex once the crucial code execution is complete.

  • Finally, we will call wg.Done() to inform the Go program that the goroutine has completed its execution.

  • The next function extract will be similar to the deposit function accepting parameters: value of type int and a waitgroup, i.e, *sync.WaitGroup.

  • Following this, we print out “Withdrawing %d from account with balance %d”, value, amount. Again, we are passing value and amount as parameters. 

  • Next, we have to update the amount in this function as well. 

amount -= value

  • Finally, we unlock the mutex- mutex.Unlock() and we call wg.Done(), much like the previous function.

  • In the main function, we define the WaitGroup.

var wg sync.WaitGroup

  • Then, we will add wgAdd(2) to this WaitGroup before creating the two goroutines.

go extract(600, &wg)

go deposit(500, &wg)


  • After then, the main function will be blocked until all of the WaitGroups have finished. The last step is to output the value from fmt.Printf("New Balance%dn", amount). We will execute the code using this.


Output:



Assessing the Output

  • We have made it clear that the initial step should be to acquire the mutex using the mutex.Lock() method in both the extract and deposit functions. Until a function successfully gets the lock, all of the functions will block.

  • When it succeeds, it will continue and enter a crucial phase, which will read and then update the account balance (amount).

  • Each function then calls mutex.Unlock() to release the lock after completing this process.

  • When using mutex, there are several situations you should be aware of that you call unlock after creating the goroutines that have acquired the lock. The unlock method must be called regardless of how the goroutines conclude. The program will reach a deadlock if you don't implement this.

Hopefully, you have a good understanding of the program and the mutex concept. And this is a straightforward method of using the reader-writer lock in Golang to manage the private data included in the goroutines. To be able to work on complex tasks later, it is crucial that you put the concept into practice after you have understood it.



Guest Author
Ankit Rajput 

Comments

Popular posts from this blog

Top 7 Web Development Trends in the Market

What's New in Selenium-Automated Testing

17 Best Demo Websites for Automation Testing Practice

Mastering Selenium WebDriver: 25+ Essential Commands for Effective Web Testing

Selenium IDE Tutorial: How to Automate Web Testing with Easy-to-Use Interface

Automation Practice: Automate Amazon like E-Commerce Website with Selenium

Mastering Selenium Practice: Automating Web Tables with Demo Examples

What Is Artificial Intelligence (AI) and How Does It Work?

Java Date Format Validation with Regular Expressions: A Step-by-Step Guide

Top 10 Highly Paid Indian CEOs in the USA