There is a task. Training, so that the issues of optimality of the decision fade into the background. There are 3 threads that need to be synchronized. The first thread collects information about files and folders. It works cyclically and recursively. Having found the information, it should stop and let threads 2 and 3 write it to a file and memory. When streams 2 and 3 have finished recording, stream 1 resumes operation and searches for the next file (folder). There should be 3 threads. Writing each found file in a new stream is not an option.
The questions are as follows:
1. Which mechanism is better to use for synchronization of threads: AutoResetEvent (its own for each of the two threads - see the code), ManualResetEvent or Semaphore.
2. How do I fix the code so that the threads start and stop when needed? I would be grateful for an explanation of why this is so, because with the Set (), Reset (), Wait () methods I played for a long time, but without success.
3. How to organize the stopping of secondary flows after the end of the primary work? I equated the null primary stream, but I think this is not the best idea.
4. And I would be grateful for an explanation of how to solve similar problems in normal, non-educational projects.
5. Is it necessary in this example to read information by secondary flows in the critical section? As I assume, the information in the reading process will not change, since the main thread waits for the completion of the secondary ones, and there is no need for a critical section.
Code:
private Queue<Nested3> collection; static int counter=100; object locked; Thread SearcherThread; Thread Handler1Thread; Thread Handler2Thread; static WaitHandle[] events; private class Nested3 { public int Val; public bool IsHandled; public Nested3(int val) { this.Val = val; IsHandled = false; } } public ARETest() { collection = new Queue<Nested3>(); events = new WaitHandle[] { new AutoResetEvent(false), new AutoResetEvent(false) }; SearcherThread = new Thread(Searcher); SearcherThread.Start(); Handler1Thread = new Thread(Handler1); Handler2Thread = new Thread(Handler2); locked = new object(); } private void Searcher() { // ΠΡΠ΅ΡΠ΅Π΄Ρ Π΄Π»Ρ Π΄Π²ΡΡ
Π·Π°Π΄Π°Ρ Π² Π΄Π²ΡΡ
ΡΠ°Π·Π½ΡΡ
ΠΏΠΎΡΠΎΠΊΠ°Ρ
. ThreadPool.QueueUserWorkItem(new WaitCallback(Handler1), events[0]); ThreadPool.QueueUserWorkItem(new WaitCallback(Handler2), events[1]); for (int i = 0; i < 3; i++) { Thread.Sleep(2); // ΠΈΠΌΠΈΡΠ°ΡΠΈΡ ΠΏΠΎΠΈΡΠΊΠ° Monitor.Enter(locked); // ΠΏΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΊΠ»Π°ΡΡΠ° Monitor Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΊΡΠΈΡΠΈΡΠ΅ΡΠΊΠΎΠΉ ΡΠ΅ΠΊΡΠΈΠΈ ΠΎΠ±ΡΡΠ»ΠΎΠ²Π»Π΅Π½ΠΎ ΡΡΠ»ΠΎΠ²ΠΈΠ΅ΠΌ Π·Π°Π΄Π°ΡΠΈ collection.Enqueue(new Nested3(++counter)); // ΠΠ°ΠΉΠ΄Π΅Π½ ΠΏΠ΅ΡΠ²ΡΠΉ ΠΏΠ°ΠΊΠ΅Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ Π΄Π»Ρ Π·Π°ΠΏΠΈΡΠΈ Π²ΡΠΎΡΠΈΡΠ½ΡΠΌΠΈ ΠΏΠΎΡΠΊΠ°ΠΌΠΈ Monitor.Exit(locked); (events[0] as AutoResetEvent).Set(); // Π·Π°ΠΏΡΡΠΊ Π²ΡΠΎΡΠΈΡΠ½ΡΡ
ΠΏΠΎΡΠΎΠΊΠΎΠ² (events[1] as AutoResetEvent).Set(); (events[0] as AutoResetEvent).Reset(); // ΡΠ±ΡΠΎΡ Π² Π½Π΅ΡΠΈΠ³Π½Π°Π»ΡΠ½ΠΎΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ (events[1] as AutoResetEvent).Reset(); // ΠΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ ΠΏΠΎΠΊΠ° Π²ΡΠ΅ Π·Π°Π΄Π°ΡΠΈ Π·Π°Π²Π΅ΡΡΠ°ΡΡΡΡ. WaitHandle.WaitAll(events); Monitor.Enter(locked); // ΠΡΠΈΡΡΠΊΠ° ΠΎΡΠ΅ΡΠ΅Π΄ΠΈ ΠΎΡ Π·Π°ΠΏΠΈΡΠ°Π½Π½ΠΎΠΉ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ collection.Dequeue(); Monitor.Exit(locked); if (i<2) Searcher(); // Π Π΅ΠΊΡΡΡΠΈΠ²Π½ΡΠΉ Π²ΡΠ·ΠΎΠ² } SearcherThread = null; // ΠΠ°ΠΏΡΡΠΊ ΠΏΠΎΡΠ»Π΅Π΄Π½Π΅Π³ΠΎ ΠΏΡΠΎΡ
ΠΎΠ΄Π° ΡΠΈΠΊΠ»Π° Π²ΡΠΎΡΠΈΡΠ½ΡΠΌΠΈ ΠΏΠΎΡΠΎΠΊΠ°ΠΌΠΈ (events[0] as AutoResetEvent).Set(); (events[1] as AutoResetEvent).Set(); } private void Handler1(object state) { var auto = (AutoResetEvent)state; do { auto.WaitOne(); // Π·Π΄Π΅ΡΡ Ρ Ρ
ΠΎΡΡ ΡΡΠΎΠ±Ρ ΠΏΠΎΡΠΎΠΊΠΈ ΠΆΠ΄Π°Π»ΠΈ ΡΠΈΠ³Π½Π°Π»Π° ΠΎΡ ΠΏΠ΅ΡΠ²ΠΈΡΠ½ΠΎΠ³ΠΎ ΠΏΠΎΡΠΎΠΊΠ° Thread.Sleep(15); // ΠΈΠΌΠΈΡΠ°ΡΠΈΡ Π·Π°ΠΏΠΈΡΠΈ Π² ΡΠ°ΠΉΠ» auto.Set(); // ΠΠ΄Π΅ΡΡ Π²ΡΠΎΡΠΈΡΠ½ΡΠΉ ΠΏΠΎΡΠΎΠΊ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π΄Π°ΡΡ ΠΏΠ΅ΡΠ²ΠΈΡΠ½ΠΎΠΌΡ ΡΠΈΠ³Π½Π°Π», ΡΡΠΎ ΠΎΠ½ Π·Π°ΠΊΠΎΠ½ΡΠΈΠ» ΠΈΡΠ΅ΡΠ°ΡΠΈΡ } while (SearcherThread != null); } private void Handler2(Object state) // ΡΠ°Π±ΠΎΡΠ°Π΅Ρ Π°Π½Π°Π»ΠΎΠ³ΠΈΡΠ½ΠΎ ΠΏΡΠ΅Π΄ΡΠ΄ΡΡΠ΅ΠΌΡ ΠΌΠ΅ΡΠΎΠ΄Ρ, Π½ΠΎ Ρ Π΄ΡΡΠ³ΠΎΠΉ Π·Π°Π΄Π΅ΡΠΆΠΊΠΎΠΉ { var auto = (AutoResetEvent)state; do { auto.WaitOne(); // Π·Π΄Π΅ΡΡ Ρ Ρ
ΠΎΡΡ ΡΡΠΎΠ±Ρ ΠΏΠΎΡΠΎΠΊΠΈ ΠΆΠ΄Π°Π»ΠΈ ΡΠΈΠ³Π½Π°Π»Π° ΠΎΡ ΠΏΠ΅ΡΠ²ΠΈΡΠ½ΠΎΠ³ΠΎ ΠΏΠΎΡΠΎΠΊΠ° Thread.Sleep(15); // ΠΈΠΌΠΈΡΠ°ΡΠΈΡ Π·Π°ΠΏΠΈΡΠΈ Π² ΡΠ°ΠΉΠ» auto.Set(); // ΠΠ΄Π΅ΡΡ Π²ΡΠΎΡΠΈΡΠ½ΡΠΉ ΠΏΠΎΡΠΎΠΊ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π΄Π°ΡΡ ΠΏΠ΅ΡΠ²ΠΈΡΠ½ΠΎΠΌΡ ΡΠΈΠ³Π½Π°Π», ΡΡΠΎ ΠΎΠ½ Π·Π°ΠΊΠΎΠ½ΡΠΈΠ» ΠΈΡΠ΅ΡΠ°ΡΠΈΡ } while (SearcherThread != null); } }