In fact, it is not appropriate to modify data with multiple threads. After all, the redis server is single-threaded and all commands are executed serially. It is only when the client sends commands concurrently that it causes serialization. Some command arrangement issues and network time differences cause data inconsistency. Although this article is about the addition and subtraction of numbers, in order to illustrate the lock situation, the atomic command incr is not intentionally used. (Recommended: redis video tutorial)
First add a simple RedisHelper, a set value, a get value, and a set concurrent lock, so that in my subsequent operations, you can Know exactly what I did.
public class RedisHelper { public RedisClient client = new RedisClient("127.0.0.1", 6379); public void Set<T>(string key, T val) { client.Set(key, val); } public T Get<T>(string key) { var result = client.Get<T>(key); return result; } public IDisposable Acquire(string key) { return client.AcquireLock(key); } }
Looking at the concurrent code below, I only added two new Threads. Two threads want to access the same key at the same time, each accessing 50,000 times. Under concurrent conditions, it is difficult for us to ensure the accuracy of the data. Please compare the output results.
static void Main(string[] args) { RedisHelper rds = new RedisHelper(); rds.Set<int>("mykey1", 0); Thread myThread1 = new Thread(AddVal); Thread myThread2 = new Thread(AddVal); myThread1.Start(); myThread2.Start(); Console.WriteLine("等待两个线程结束"); Console.ReadKey(); } public static void AddVal() { RedisHelper rds = new RedisHelper(); for (int i = 0; i < 50000; i++) { int result = rds.Get<int>("mykey1"); rds.Set<int>("mykey1", result + 1); } Console.WriteLine("线程结束,输出" + rds.Get<int>("mykey1")); }
Yes, with our single thread, running two 50000 will output 100000. Now two concurrent threads are running at the same time. Due to concurrency, the data results are often not what we want. So how to solve this problem, Redis is already ready for us!
You can see that one of the methods in my RedisHelper is public IDisposable Acquire(string key). You can also see that it returns IDisposable, which proves that we need to manually release resources.
The AcquireLock inside the method is the key point. It is like asking for a lock in redis. The locked resource can only be accessed by a single thread and will not be get or set by two threads at the same time. These two threads must be carried out alternately. Of course, the alternation here does not mean once for you and once for me. It may also be for you multiple times and once for me. See the code below.
static void Main(string[] args) { RedisHelper rds = new RedisHelper(); rds.Set<int>("mykey1", 0); Thread myThread1 = new Thread(AddVal); Thread myThread2 = new Thread(AddVal); myThread1.Start(); myThread2.Start(); Console.WriteLine("等待两个线程结束"); Console.ReadKey(); } public static void AddVal() { RedisHelper rds = new RedisHelper(); for (int i = 0; i < 50000; i++) { using (rds.Acquire("lock")) { int result = rds.Get<int>("mykey1"); rds.Set<int>("mykey1", result + 1); } } Console.WriteLine("线程结束,输出" + rds.Get<int>("mykey1")); }
You can see that I used using to call my Acquire method to acquire the lock.
The final output result is 100000, which is the correct result we want. The previous 8W is because one of the two threads ended execution first.
Also, during the official use process, it is recommended to delete the lock given to us after use, and add an expiration time, using expire.
To avoid unexpected exit during program execution, the lock will always exist and the locked data may not be updated or obtained in the future.
You can also try not to set expire. When the program just starts executing, close the console, re-run the program, and get the value you locked in the redis-cli operation console, and it will be obtained forever. Less than.
All machines connected to this redis instance can only have one lock that acquires the specified name at the same time.
The following is how StackExchange.Redis is written
var info = "name-"+Environment.MachineName; //如果5秒不释放锁 自动释放。避免死锁 if (db.LockTake("name", info, TimeSpan.FromSeconds(5))) { try { } catch (Exception ex) { } finally { db.LockRelease("name", token); } }
More redis For knowledge, please pay attention to the redis database tutorial column.
The above is the detailed content of Simple application introduction of Redis lock. For more information, please follow other related articles on the PHP Chinese website!