README.rst 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. range-lock - Multithread range lock for Vec
  2. ===========================================
  3. `https://bues.ch/ <https://bues.ch/>`_
  4. Provides multi-threaded access to a single Vec<T> instance. Any thread can atomically request access to a slice of the Vec. Such access is granted, if no other thread is simultaneously holding the right to access an overlapping slice.
  5. Usage
  6. =====
  7. Add this to your Cargo.toml:
  8. .. code:: toml
  9. [dependencies]
  10. range-lock = "0.1"
  11. RangeLock example usage
  12. -----------------------
  13. General purpose RangeLock:
  14. .. code:: rust
  15. extern crate range_lock;
  16. use range_lock::RangeLock;
  17. use std::sync::{Arc, Barrier};
  18. use std::thread;
  19. // The data that will simultaneously be accessed from the threads.
  20. let data = vec![10, 11, 12, 13];
  21. // Embed the data in a RangeLock
  22. // and clone atomic references to it for the threads.
  23. let data_lock0 = Arc::new(RangeLock::new(data));
  24. let data_lock1 = Arc::clone(&data_lock0);
  25. let data_lock2 = Arc::clone(&data_lock0);
  26. // Thread barrier, only for demonstration purposes.
  27. let barrier0 = Arc::new(Barrier::new(2));
  28. let barrier1 = Arc::clone(&barrier0);
  29. // Spawn first thread.
  30. let thread0 = thread::spawn(move || {
  31. {
  32. let mut guard = data_lock0.try_lock(0..2).expect("T0: Failed to lock 0..2");
  33. guard[0] = 100; // Write to data[0]
  34. }
  35. barrier0.wait(); // Synchronize with second thread.
  36. {
  37. let guard = data_lock0.try_lock(2..4).expect("T0: Failed to lock 2..4");
  38. assert_eq!(guard[0], 200); // Read from data[2]
  39. }
  40. });
  41. // Spawn second thread.
  42. let thread1 = thread::spawn(move || {
  43. {
  44. let mut guard = data_lock1.try_lock(2..4).expect("T1: Failed to lock 2..4");
  45. guard[0] = 200; // Write to data[2]
  46. }
  47. barrier1.wait(); // Synchronize with first thread.
  48. {
  49. let guard = data_lock1.try_lock(0..2).expect("T1: Failed to lock 0..2");
  50. assert_eq!(guard[0], 100); // Read from data[0]
  51. }
  52. });
  53. // Wait for both threads to finish and check result.
  54. thread0.join().expect("Thread 0 failed");
  55. thread1.join().expect("Thread 1 failed");
  56. // Unwrap the data from the lock.
  57. let data = Arc::try_unwrap(data_lock2).expect("Arc unwrap failed").into_inner();
  58. // Check the data that has been modified by the threads.
  59. assert_eq!(data, vec![100, 11, 200, 13]);
  60. RepRangeLock example usage
  61. --------------------------
  62. The RepRangeLock is a restricted range lock, that provides interleaved patterns of slices to the threads.
  63. Locking a RepRangeLock is more lightweight than locking a RangeLock.
  64. Please see the example below.
  65. .. code:: rust
  66. use range_lock::RepRangeLock;
  67. use std::sync::Arc;
  68. use std::thread;
  69. let data = vec![1, 2, 3, 4, 5, 6, // <- cycle 0
  70. 7, 8, 9, 10, 11, 12]; // <- cycle 1
  71. // ^--^ ^---^ ^----^
  72. // | | |
  73. // offset-0 offset-1 offset-2
  74. let lock = Arc::new(RepRangeLock::new(data,
  75. 2, // slice_len: Each slice has 2 elements.
  76. 3)); // cycle_len: Each cycle has 3 slices (offsets).
  77. let lock0 = Arc::clone(&lock);
  78. let lock1 = Arc::clone(&lock);
  79. let lock2 = Arc::clone(&lock);
  80. let thread0 = thread::spawn(move || {
  81. // Lock slice offset 0:
  82. let mut guard = lock0.try_lock(0).expect("Failed to lock offset.");
  83. // Read:
  84. assert_eq!(guard[0][0], 1); // Cycle 0, Slice element 0
  85. assert_eq!(guard[0][1], 2); // Cycle 0, Slice element 1
  86. // let _ = guard[0][2]; // Would panic. Slice len is only 2.
  87. assert_eq!(guard[1][0], 7); // Cycle 1, Slice element 0
  88. assert_eq!(guard[1][1], 8); // Cycle 1, Slice element 1
  89. // let _ = guard[2][0]; // Would panic: The data vec is only 2 repeat cycles long.
  90. // Write:
  91. guard[0][0] = 10; // Cycle 0, Slice element 0
  92. guard[0][1] = 20; // Cycle 0, Slice element 1
  93. // guard[0][2] = 42; // Would panic: Slice len is only 2.
  94. guard[1][0] = 30; // Cycle 1, Slice element 0
  95. guard[1][1] = 40; // Cycle 1, Slice element 1
  96. // guard[2][0] = 42; // Would panic: The data vec is only 2 repeat cycles long.
  97. });
  98. let thread1 = thread::spawn(move || {
  99. // Lock slice offset 1:
  100. let mut guard = lock1.try_lock(1).expect("Failed to lock offset.");
  101. guard[0][0] = 100; // Cycle 0, Slice element 0
  102. guard[0][1] = 200; // Cycle 0, Slice element 1
  103. guard[1][0] = 300; // Cycle 1, Slice element 0
  104. guard[1][1] = 400; // Cycle 1, Slice element 1
  105. });
  106. let thread2 = thread::spawn(move || {
  107. // Lock slice offset 2:
  108. let mut guard = lock2.try_lock(2).expect("Failed to lock offset.");
  109. guard[0][0] = 1000; // Cycle 0, Slice element 0
  110. guard[0][1] = 2000; // Cycle 0, Slice element 1
  111. guard[1][0] = 3000; // Cycle 1, Slice element 0
  112. guard[1][1] = 4000; // Cycle 1, Slice element 1
  113. });
  114. thread0.join();
  115. thread1.join();
  116. thread2.join();
  117. // Get the data that has been modified by the threads.
  118. let data = Arc::try_unwrap(lock).expect("Thread is still using data.").into_inner();
  119. assert_eq!(data,
  120. vec![10, 20, 100, 200, 1000, 2000,
  121. 30, 40, 300, 400, 3000, 4000]);
  122. TODOs for future releases
  123. =========================
  124. The following new features might be candidates for future releases:
  125. * Optimize the range overlap search algorithm.
  126. * Sleeping lock, in case of lock contention.
  127. * Add support for arrays.
  128. License
  129. =======
  130. Copyright (c) 2021 Michael Buesch <m@bues.ch>
  131. Licensed under the Apache License version 2.0 or the MIT license, at your option.