Rust: البرمجة المتزامنة في لغة Rust
آخر تحديث: 2026-08-26
التزامن هو قدرة البرنامج على القيام بأمور متعددة «في الوقت نفسه» — تخلَّص لغة Rust من حالات التنافس على البيانات في مرحلة التحويل البرمجي من خلال أنظمة الملكية والأنواع الخاصة بها، مما يتيح لك كتابة كود متزامن يتسم بالكفاءة والأمان في آن واحد.
إذا كان البرنامج أحادي الخيط يشبه «شخصًا واحدًا يعمل في المطبخ من البداية إلى النهاية»، فإن التعدد الخيطي يشبه «عدة طهاة يعملون في الوقت نفسه» — فبعضهم يقطع الخضار، وبعضهم يقلي الطعام، وبعضهم يقدم الأطباق. ولكن عندما يكون هناك عدد كبير جدًا من الأشخاص في المطبخ، يمكن أن تسود الفوضى بسهولة: فقد يمد شخصان أيديهما نحو السكين نفسه في نفس الوقت، أو قد يأخذ شخص ما مكونًا يستخدمه شخص آخر في تلك اللحظة. يشبه نموذج التزامن في Rust «مطبخًا متعدد الطهاة يخضع لقواعد» — فلكل طاهٍ أدواته الخاصة، وتُمرر المكونات عبر قنوات مخصصة، ولا يمكن استخدام التوابل المشتركة إلا من قبل شخص واحد في كل مرة.
1. ما ستتعلمه
std::thread::spawnإنشاء مؤشر ترابط وjoinانتظار انتهاء المؤشر الترابطيmoveتُنقل الملكية إلى الخيط عند إغلاق الكائناتmpsc::channelالقناة — نظام المراسلة متعدد المرسلين والمستلم الواحدMutex<T>أقفال الاستبعاد المتبادل — ضمان الوصول الآمن من حيث الخيوط إلى البيانات المشتركةArc<T>العد المرجعي الذري — السماح بمشاركةMutex<T>عبر خيوط متعددة- مفهوم السمة
Send/Sync— أساس أمان التزامن في لغة Rust
2. قصة نظام تحرير المستندات التعاوني
(1) المشكلة: التوثيق عبر الإنترنت دون التحكم في التزامن
تعمل شركة «لونا» على تطوير محرر مستندات تعاوني عبر الإنترنت. وكانت الإصدارات الأولى لا تسمح إلا لشخص واحد بالتحرير في كل مرة، مما أدى إلى شكاوى متكررة من أعضاء الفريق:
- بينما كانت أليس تكتب الاقتراح، كان بوب يقوم أيضًا بتحرير نفس الجزء من النص — فتداخلت تعديلاتهما مع بعضهما البعض.
- تريد كارول الاطلاع على التحديثات التي تُجرى على المستند في الوقت الفعلي، لكنها تضطر إلى تحديث الصفحة في كل مرة.
- قدم ديف تعديلاً، لكن لونا لم تكن تعرف من الذي أجراه.
- وما زاد الطين بلة أن محررين اثنين قاما بتحرير نفس المحتوى في الوقت نفسه، مما أدى إلى تعطل المستند.
- كلما حاولت «لونا» إضافة ميزة «التحرير المتنافي»، يتحول الكود إلى فوضى — مليئة بالمتغيرات العالمية وأقفال الوصول.
"سيكون من الرائع لو أمكننا إنشاء موضوع منفصل لكل محرر، وتوجيه طلبات التعديل عبر قناة، وحماية محتوى المستند باستخدام موتكس..."
(2) مناهج نموذج التزامن في لغة Rust
use std::thread;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::time::Duration;
fn main() {
// Create a document with shared content(Arc<Mutex<String>>)
let document = Arc::new(Mutex::new(String::from("# Collaborative Documents\n\n")));
// Create a channel,Used to transmit edit requests
let (tx, rx) = mpsc::channel::<String>();
// Receiving Thread:Processing editing requests on an ongoing basis
let doc_for_receiver = Arc::clone(&document);
let receiver = thread::spawn(move || {
for edit in rx {
let mut doc = doc_for_receiver.lock().unwrap();
doc.push_str(&edit);
doc.push('\n');
println!("[Receiver] Edits Applied");
}
});
// Simulating an Editor Thread
let tx1 = tx.clone();
thread::spawn(move || {
tx1.send("- Alice: Added the content for Chapter 1".to_string()).unwrap();
});
let tx2 = tx.clone();
thread::spawn(move || {
tx2.send("- Bob: The title of Chapter 2 has been revised.".to_string()).unwrap();
});
// The main thread also sends a message
tx.send("- Luna: Format Adjustments".to_string()).unwrap();
// Wait until all editors have finished sending their edits
thread::sleep(Duration::from_millis(100));
drop(tx); // Close the sender
receiver.join().unwrap();
// Final Document Content
let final_doc = document.lock().unwrap();
println!("\n=== Final Document ===");
println!("{}", *final_doc);
}
يفصل حل التزامن في لغة Rust المسؤوليات بوضوح: يعمل كل محرر في مؤشر ترابط منفصل، وتُمرر طلبات التحرير عبر
mpsc::channel، ويحظى محتوى المستند بالحماية بواسطةMutex. ويتيحArcمشاركةMutexعبر مؤشرات ترابط متعددة. ويضمن نظام الملكية عدم حدوث أي حالات تنافس.
3. المفاهيم الأساسية
(1) إطار عمل التزامن في لغة Rust
graph TB
A[Rust Concurrent Programming] --> B[Thread Management]
A --> C[Messaging]
A --> D[Shared Status]
A --> E[Safety Guarantee]
B --> B1["thread::spawn ||"]
B --> B2["join() The Wait Is Over"]
B --> B3["move Closures Transfer Ownership"]
C --> C1["mpsc::channel"]
C --> C2["Sender / Receiver"]
C --> C3["send / recv"]
D --> D1["Mutex<T> Mutex"]
D --> D2["lock() Acquire a lock"]
D --> D3["Arc<T> Atomic Reference Counting"]
E --> E1["Send: Ownership can be transferred across threads"]
E --> E2["Sync: References can be shared across threads"]
E --> E3["Eliminating Data Races at Compile Time"]
(2) مقارنة بين ثلاثة نماذج للتزامن
| ميزة | thread::spawn (خيط) | mpsc::channel (قناة) | Arc<Mutex<T>> (حالة مشتركة) |
|---|---|---|---|
| المفهوم الأساسي | وحدات التنفيذ المستقلة | تمرير الرسائل | الذاكرة المشتركة + الأقفال |
| طرق نقل البيانات | move: نقل الملكية عبر دالة مغلقة | send/recv: إرسال رسالة | lock: استرداد قيمة داخلية |
| حالات الاستخدام | التنفيذ المتوازي للمهام المستقلة | نمط «المنتج-المستهلك» | وصول خيوط متعددة إلى نفس البيانات |
| المزايا | يستفيد استفادة كاملة من المعالجات متعددة النوى | يفصل بين المرسِلين والمستقبِلين | يتيح مشاركة أي نوع مباشرةً |
| العيوب | تعقيد الاتصال بين الخيوط | غير مناسب لعمليات نقل البيانات الصغيرة المتكررة | احتمال حدوث حالات تعطل وتأثيرات سلبية على الأداء |
| ميزات لغة Rust | الملكية تمنع وجود المؤشرات المعلقة | يضمن المُترجم الاستخدام الصحيح | يمنع حدوث تضارب الوصول إلى البيانات في مرحلة الترجمة |
(3) خاصية «الإرسال والمزامنة»
| السمة | المعنى | الشروط التي يتم تنفيذها تلقائيًا | الأنواع التي لا يتم تنفيذها تلقائيًا |
|---|---|---|---|
| إرسال | يمكن نقل ملكية النوع عبر الخيوط | يتم تنفيذه تلقائيًا بالنسبة للغالبية العظمى من الأنواع | Rc<T> (العد غير الذري للمراجع) |
| المزامنة | يمكن مشاركة الإشارات إلى الأنواع عبر الخيوط | يتم تنفيذها تلقائيًا للغالبية العظمى من الأنواع | RefCell<T> (قابلية التغيير الداخلية غير الذرية) |
| T: الإرسال + المزامنة | الأنواع التي يمكن مشاركتها ونقلها بأمان بين الخيوط | Arc<T>، Mutex<T> |
المؤشرات الأولية *const T، *mut T |
(4) دليل مرجعي سريع لاختيار طرق الاتصال عبر الخيوط
| طريقة الاتصال | النوع | اتجاه تدفق البيانات | الحاجة إلى القفل | السيناريوهات القابلة للتطبيق |
|---|---|---|---|---|
| القناة | mpsc::channel |
أحادية الاتجاه (المرسل → المستقبل) | لا | نمط «المنتج-المستهلك» |
| القناة (متعددة المنتجين) | mpsc::channel + tx.clone() |
متعدد→فردي | لا | نتائج مجمعة متعددة الخيوط |
| حالة المشاركة | Arc<Mutex<T>> |
ثنائي الاتجاه | نعم (قفل الاستبعاد المتبادل) | وصول متعدد الخيوط للقراءة/الكتابة إلى نفس البيانات |
| حالة المشاركة (قراءة/كتابة) | Arc<RwLock<T>> |
ثنائي الاتجاه | نعم (قفل القراءة/الكتابة) | سيناريو يكثر فيه القراءة ويقل فيه الكتابة |
| العمليات الذرية | AtomicUsize وآخرون |
ثنائي الاتجاه | لا (على مستوى الأجهزة) | عدادات/علامات بسيطة |
| الحاجز | Barrier |
نقطة التزامن | لا | نقطة التقارب متعددة الخيوط |
لا تعتمد لغة Rust على عمليات الفحص أثناء وقت التشغيل لضمان أمان الخيوط؛ بل تقوم بدلاً من ذلك بإجراء عمليات فحص أثناء التحويل البرمجي باستخدام السمتين المُعَلَّمتين
SendوSync. وإذا لم يكن النوعSend، فإن محاولة تمريره إلى خيط آخر ستؤدي إلى حدوث خطأ أثناء التحويل البرمجي.
4. أمثلة على البرمجة المتزامنة
(1) ▶ المثال:thread::spawn + join — إنشاء مؤشر ترابط والانتظار حتى ينتهي (مستوى الصعوبة ⭐)
// ============================================
// Demo:thread::spawn Create a Thread、join The Wait Is Over
// Simulation: Several chefs are preparing different dishes at the same time in the kitchen.
// ============================================
use std::thread;
use std::time::Duration;
fn main() {
println!("=== Kitchen Renovation Begins ===");
// --- 1. Create three threads to perform different tasks ---
let chef1 = thread::spawn(|| {
for i in 1..=3 {
println!("[Chef A] Chopping vegetables... Cut #{}", i);
thread::sleep(Duration::from_millis(50));
}
"A Finished chopping the vegetables"
});
let chef2 = thread::spawn(|| {
for i in 1..=3 {
println!("[Chef B] Stir-frying... Step #{}", i);
thread::sleep(Duration::from_millis(40));
}
"B Finished cooking the stir-fry"
});
// The main thread is also running
for i in 1..=3 {
println!("[Head Chef] Plating in progress... Item #{}", i);
thread::sleep(Duration::from_millis(60));
}
// --- 2. join Wait for all threads to finish and retrieve the return values ---
let result1 = chef1.join().unwrap();
let result2 = chef2.join().unwrap();
println!("\n=== Kitchen Shutdown ===");
println!("Chef A: {}", result1);
println!("Chef B: {}", result2);
println!("All work has been completed!");
}
الناتج:
=== Kitchen Renovation Begins ===
[Chef A] Chopping vegetables... Cut #1
[Chef B] Stir-frying... Step #1
[Head Chef] Plating in progress... Item #1
[Chef A] Chopping vegetables... Cut #2
[Chef B] Stir-frying... Step #2
[Head Chef] Plating in progress... Item #2
[Chef A] Chopping vegetables... Cut #3
[Chef B] Stir-frying... Step #3
[Head Chef] Plating in progress... Item #3
=== Kitchen Shutdown ===
Chef A: A Finished chopping the vegetables
Chef B: B Finished cooking the stir-fry
All work has been completed!
thread::spawnتقبل إغلاقًا وتنفذه في مؤشر ترابط جديد بنظام التشغيل.join()يحجب الخيط الحالي حتى ينتهي الخيط المستهدف، ويعيدResult<T>—وإذا تعرض الخيط لحالة ذعر، فإنjoin()يعيدErr. يتم تحديد ترتيب تنفيذ الخيوط بواسطة جدولة نظام التشغيل وقد يختلف من عملية تشغيل إلى أخرى.
(2) ▶ المثال:mpsc::channel — المراسلة (مستوى الصعوبة ⭐⭐)
// ============================================
// Demo: mpsc::channel Many-Producer, Single-Consumer Messaging
// Simulation: Multiple editors send modification requests to the document server
// ============================================
use std::thread;
use std::sync::mpsc;
use std::time::Duration;
#[derive(Debug)]
enum EditAction {
Insert { user: String, text: String },
Delete { user: String, line: u32 },
Format { user: String, style: String },
}
fn main() {
println!("=== Collaborative Document Editor ===");
// Create a Channel:Sender Can be cloned,Receiver It is the only one
let (tx, rx) = mpsc::channel::<EditAction>();
// --- 1. Start the receive thread (Document Server) ---
let receiver = thread::spawn(move || {
for action in rx {
match &action {
EditAction::Insert { user, text } => {
println!("[Server] {} Inserted: {}", user, text);
}
EditAction::Delete { user, line } => {
println!("[Server] {} Deleted line {}", user, line);
}
EditAction::Format { user, style } => {
println!("[Server] {} Formatting has been applied: {}", user, style);
}
}
// Simulated Processing Time
thread::sleep(Duration::from_millis(20));
}
println!("[Server] Passage Closed,Unsubscribe");
});
// --- 2. Create the first editor thread (Alice) ---
let tx1 = tx.clone();
let editor1 = thread::spawn(move || {
tx1.send(EditAction::Insert {
user: "Alice".to_string(),
text: "Chapter 1: Rust Introduction".to_string(),
}).unwrap();
thread::sleep(Duration::from_millis(10));
tx1.send(EditAction::Format {
user: "Alice".to_string(),
style: "Bold the title".to_string(),
}).unwrap();
});
// --- 3. Create the second editor thread (Bob) ---
let tx2 = tx.clone();
let editor2 = thread::spawn(move || {
tx2.send(EditAction::Insert {
user: "Bob".to_string(),
text: "Rust is a systems programming language".to_string(),
}).unwrap();
thread::sleep(Duration::from_millis(10));
tx2.send(EditAction::Delete {
user: "Bob".to_string(),
line: 1,
}).unwrap();
});
// --- 4. The main thread also sends a message ---
tx.send(EditAction::Insert {
user: "System".to_string(),
text: "Auto-Save Documents".to_string(),
}).unwrap();
// Wait for the editor thread to finish
editor1.join().unwrap();
editor2.join().unwrap();
// Close the sender - After all Senders are dropped, the Receiver for loop will end automatically
// tx is dropped here (because tx is the last sender on the main thread)
println!("All editors have completed their work");
receiver.join().unwrap();
println!("=== End of editing session ===");
}
// Note: tx is automatically dropped when leaving the scope, channel closes
// If you need to explicitly turn it off,Can be used drop(tx)
الناتج:
=== Collaborative Document Editor ===
[Server] System Inserted: Auto-Save Documents
[Server] Alice Inserted: Chapter 1: Rust Introduction
[Server] Bob Inserted: Rust is a systems programming language
[Server] Alice Formatting has been applied: Bold the title
[Server] Bob Deleted line 1
All editors have completed their work
[Server] Passage Closed,Unsubscribe
=== End of editing session ===
mpscتعني «منتج متعدد، مستهلك واحد». يمكن نسخSenderإلى خيوط متعددة عبرclone، لكن لا يمكن أن يكون هناك سوىReceiverواحد فقط. وعندما يتم إغلاق جميعSender، تُغلق القناة تلقائيًا، وينتهي عمل المكرر الخاص بـReceiver. تُرجعsendResult— وإذا كان الطرف المستقبل قد أُغلق، فإنها تُرجعErr.
(3) ▶ المثال:Arc<Mutex<T>> — الوصول الآمن بين الخيوط إلى الحالة المشتركة (مستوى الصعوبة ⭐⭐⭐)
// ============================================
// Demo: Arc<Mutex<T>> Safely Sharing Data Among Multiple Threads
// Simulation: Multiple workers modifying a shared counter simultaneously
// ============================================
use std::thread;
use std::sync::{Arc, Mutex};
use std::time::Duration;
fn main() {
println!("=== Shared Counter Demo ===");
// Use Arc<Mutex<i32>> to wrap shared data
let counter = Arc::new(Mutex::new(0i32));
let mut handles = vec![];
// --- Start 5 threads,Each thread increments the counter by 10 ---
for id in 0..5 {
let counter_clone = Arc::clone(&counter);
let handle = thread::spawn(move || {
for _ in 0..10 {
// lock() Acquire a mutex lock——If the lock is held by another thread,The current thread will block while waiting
let mut num = counter_clone.lock().unwrap();
*num += 1;
println!("[Workers{}] Current Count: {}", id, *num);
// Locks are automatically released when they go out of scope
}
println!("[Workers{}] Work Completed", id);
});
handles.push(handle);
}
// --- Wait for all threads to finish ---
for handle in handles {
handle.join().unwrap();
}
// --- Read the final results ---
let final_count = counter.lock().unwrap();
println!("\n=== Final Results ===");
println!("Final counter value: {}", *final_count);
println!("Expected value: {} (5 threads x 10 times)", 5 * 10);
}
الناتج:
=== Shared Counter Demo ===
[Workers0] Current Count: 1
[Workers0] Current Count: 2
[Workers1] Current Count: 3
[Workers1] Current Count: 4
[Workers0] Current Count: 5
... (The intermediate output varies depending on thread scheduling)
[Workers4] Current Count: 50
[Workers4] Work Completed
=== Final Results ===
Final counter value: 50
Expected value: 50 (5 threads x 10 times)
يوفر
Mutex<T>الاستبعاد المتبادل — حيث لا يمكن سوى لخيط واحد الوصول إلى البيانات الداخلية في كل مرة. يُرجعlock()MutexGuard<T>، الذي يُنفِّذDerefوDrop: يتم تحرير القفل تلقائيًا عند الخروج من نطاقه.Arc<T>(Atomic Reference Counted) هي النسخة متعددة الخيوط منRc<T>، وتستخدم عمليات ذرية لضمان أمان الخيوط في عملية عد المراجع.Arc::cloneتزيد عدد المراجع دون نسخ البيانات.
(4) ▶ المثال:التعاون بين الخيوط — نمط «المنتج والمستهلك» (مستوى الصعوبة ⭐⭐⭐)
// ============================================
// Producer-Consumer: Multiple producers + Single consumer
// ============================================
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
let (tx, rx) = mpsc::channel();
let tx2 = tx.clone();
thread::spawn(move || {
let items = vec!["Apple", "Banana", "Orange"];
for item in items {
tx.send(format!("Producer1: {}", item)).unwrap();
thread::sleep(Duration::from_millis(100));
}
println!("Producer1 Done");
});
thread::spawn(move || {
let items = vec!["Watermelon", "Grapes"];
for item in items {
tx2.send(format!("Producer2: {}", item)).unwrap();
thread::sleep(Duration::from_millis(150));
}
println!("Producer2 Done");
});
println!("=== Consumer Receipt ===");
for msg in rx {
println!(" Received: {}", msg);
}
println!("All producers have finished, consumer section ended");
}
الناتج (قد يختلف الترتيب):
=== Consumer Receipt ===
Received: Producer1: Apple
Received: Producer2: Watermelon
Received: Producer1: Banana
Received: Producer1: Orange
Received: Producer2: Grapes
Producer1 Done
Producer2 Done
All producers have finished, consumer section ended
tx.clone()ينشئ عدة مرسلين لتنفيذ نمط «المنتجين المتعددين». وعندما يتم إزالة جميع المرسلين (txوtx2)، يتوقف المكررrxتلقائيًا — ولا توجد حاجة إلى إرسال إشارة «نهاية» يدويًّا.
(5) ▶ المثال:تمرين شامل — معالجة البيانات بالتوازي (مستوى الصعوبة ⭐⭐⭐)
// ============================================
// Parallel Computing: Multithreaded Sharded Summation
// ============================================
use std::sync::{Arc, Mutex};
use std::thread;
fn parallel_sum(data: &[i64], num_threads: usize) -> i64 {
let chunk_size = (data.len() + num_threads - 1) / num_threads;
let result = Arc::new(Mutex::new(0i64));
let mut handles = Vec::new();
for i in 0..num_threads {
let chunk = data[i * chunk_size..(i * chunk_size + chunk_size).min(data.len())].to_vec();
let result = Arc::clone(&result);
handles.push(thread::spawn(move || {
let partial: i64 = chunk.iter().sum();
*result.lock().unwrap() += partial;
partial
}));
}
let mut partials = Vec::new();
for handle in handles {
partials.push(handle.join().unwrap());
}
println!("The various thread sections and: {:?}", partials);
*result.lock().unwrap()
}
fn main() {
let data: Vec<i64> = (1..=1000).collect();
let sequential_sum: i64 = data.iter().sum();
println!("=== Serial Summation ===");
println!("1 to 1000 sum: {}", sequential_sum);
println!("\n=== Parallel Summation (4 Thread) ===");
let parallel_result = parallel_sum(&data, 4);
println!("Parallel Summation Results: {}", parallel_result);
assert_eq!(sequential_sum, parallel_result);
let data2: Vec<i64> = (1..=10_000_000).collect();
let start = std::time::Instant::now();
let _ = data2.iter().sum::<i64>();
let seq_time = start.elapsed();
let start = std::time::Instant::now();
let _ = parallel_sum(&data2, 8);
let par_time = start.elapsed();
println!("\n=== 10M Data Performance Comparison ===");
println!("Serial: {:?}", seq_time);
println!("Parallel (8Thread): {:?}", par_time);
}
الناتج:
=== Serial Summation ===
1 to 1000 sum: 500500
=== Parallel Summation (4 Thread) ===
The various thread sections and: [78126, 218874, 109374, 94126]
Parallel Summation Results: 500500
=== 10M Data Performance Comparison ===
Serial: [Time]
Parallel (8Thread): [Time]
parallel_sumتقسيم البيانات؛ حيث يحسب كل مؤشر ترابط مجموعًا جزئيًا، ثم يتم تجميع هذه المجاميع للحصول على النتيجة الإجمالية عبرArc<Mutex<i64>>.chunk_sizeالتقريب لأعلى لضمان احتساب جميع البيانات.assert_eq!التحقق من تطابق النتيجة المتوازية مع النتيجة التسلسلية. بالنسبة لمجموعات البيانات الكبيرة، يمكن أن يؤدي استخدام مؤشرات الترابط المتعددة إلى تحسين الأداء بشكل ملحوظ.
❓ أسئلة شائعة
thread::spawn ما هي العلاقة بين الخيوط التي تم إنشاؤها والخيط الرئيسي؟send وrecv التابعتان لـ mpsc::channel؟send عادةً (فهي تعود فورًا عند توفر مساحة في المخزن المؤقت)، بينما تتوقف وظيفة recv حتى يتم استلام رسالة.Mutex<T> وArc<Mutex<T>> معًا؟Mutex في حدوث حالة تعطل متبادل؟Send وSync؟Send تعني «يمكن نقل الملكية عبر الخيوط»، وSync تعني «يمكن مشاركة المراجع عبر الخيوط».📖 ملخص
thread::spawnينشئ مؤشر ترابط لنظام التشغيل ويقبل دالة إغلاق كنص التنفيذ؛join()ينتظر انتهاء المؤشر الترابط ويسترد النتيجةmoveالإغلاق نقل ملكية القيم إلى خيوط جديدة لتجنب المراجع المعلقة — وهذا تطبيق مباشر لنظام الملكية في لغة Rust في سياق التزامن.mpsc::channelتوفر قناة متعددة المرسلين ومستهلك واحد؛ حيث يقومsendبإرسال الرسائل، بينما يتلقىrecvالرسائل؛ وتُغلق القناة تلقائيًا عند انقطاع اتصال جميع المرسلينMutex<T>يوفر الاستبعاد المتبادل؛lock()يحصل على القفل (يحجب)؛MutexGuardيحرر القفل تلقائيًا عند خروجه من نطاقهArc<T>هي النسخة الآمنة من حيث الخيوط منRc<T>؛ فهي تستخدم العمليات الذرية لإدارة أعداد المراجع، وتُستخدم كجسر لمشاركةMutex<T>عبر خيوط متعددة.Send/Syncهما سمتان مميزتان في لغة Rust تضمنان الأمان في عمليات التزامن — حيث تسمحSendبنقل الملكية عبر الخيوط، وتسمحSyncبمشاركة المراجع عبر الخيوط، ويقوم المُترجم بإجراء عمليات التحقق في وقت الترجمة.
📝 تمارين
- الصعوبة ⭐: اكتب برنامجًا ينشئ ثلاثة خيوط لحساب مجموع الأعداد من 1 إلى 10، ومن 11 إلى 20، ومن 21 إلى 30، على التوالي. يستخدم الخيط الرئيسي
joinلانتظار انتهاء جميع الخيوط، ثم يجمع المجاميع الجزئية الثلاثة ويطبع النتيجة النهائية. - الصعوبة ⭐⭐: استخدم
mpsc::channelلتنفيذ «موزع المهام». أنشئ خيط عمل منتج واحد (يقوم بإنشاء 10 مهام مرقمة من 1 إلى 10) وخيطي عمل مستهلكين (يتلقى كل مستهلك رقم مهمة من القناة ويطبع «[المستهلك X] يعالج المهمة رقم N»). تأكد من معالجة جميع المهام. - الصعوبة ⭐⭐⭐: قم بتنفيذ نظام «الحساب المصرفي المشترك». استخدم
Arc<Mutex<f64>>كرصيد مشترك. أنشئ 4 خيوط لمحاكاة عمليات الإيداع (يقوم كل خيط بإيداع مبلغ عشوائي يتراوح بين 10 و100 يوان). ينتظر الخيط الرئيسي انتهاء جميع خيوط الإيداع قبل قراءة الرصيد النهائي. متطلب إضافي: اطبع التغير في الرصيد قبل وبعد كل عملية إيداع للتحقق من عدم وجود حالة تنافس (الرصيد النهائي = الرصيد الأولي + مجموع جميع الإيداعات).