There are four threads (1, 2, 3, and 4) to write data synchronously ...... C ++ 11 Implementation, google
Recently I am studying multithreading, the title is derived from the first article of "second kill multithreading" (http://blog.csdn.net/morewindows/article/details/7392749) by Mr MoreWindows)
Excerpt:
Question 5 (Google interview)
There are four threads: 1, 2, 3, and 4. The function of thread 1 is output 1, the function of thread 2 is output 2, and so on ...... there are now four files, ABCD. It is empty initially. Four files are in the following format:
A: 1 2 3 4 1 2 ....
B: 2 3 4 1 2 3 ....
C: 3 4 1 2 3 4 ....
D: 4 1 2 3 4 1 ....
Design the program.
The code is implemented as follows:
1 # include <iostream> 2 # include <string> 3 # include <thread> 4 # include "Semaphore. h "5 6 constexpr unsigned MAX_COUNT = 10; 7 constexpr unsigned MAX_THREAD = 4; 8 9 unsigned getNext (unsigned current, bool order) {10 if (order) {11 unsigned next = current + 1; 12 return next % MAX_THREAD; // Positive Sequence 13} else {14 unsigned next = current-1; 15 return next % MAX_THREAD; // reverse 16} 17} 18 19 class File20 {2 1 public: 22 File (const std: string & name = "0") 23: m_name (name) 24, m_buffer (MAX_COUNT, '0') 25, m_pos (0) {26 27} 28 29 void write (char c) {30 m_buffer.at (m_pos ++) = c; 31} 32 33 std: string getName () const {34 return m_name; 35} 36 std: string getData () const {37 return m_buffer; 38} 39 private: 40 std: string m_name; 41 std: string m_buffer; 42 size_t m_pos; 43}; 44 45 Semaphore t1 (1), t2 (1), t3 (1), t4 (1 ); 46 Semaphore * semaphoreArray [MAX_THREAD] ={& t1, & t2, & t3, & t4}; 47 File files [MAX_THREAD] = {File (""), file ("B"), File ("C"), File ("D")}; 48 unsigned currentFile [MAX_THREAD] = {0, 1, 2, 3 }; // The current file id49 50 void write (unsigned threadId) that each thread should write {51 const char c = '1' + threadId; 52 auto & fid = currentFile [threadId]; 53 // auto fid = threadId; 54 auto nextThreadId = getNext (threadId, true); // positive 55 Unsigned count = 0; 56 while (MAX_COUNT! = Count) {57 semaphoreArray [threadId]-> wait (); 58 // Write File 59 files [fid]. write (c); 60 // pass the file to the next thread. 61 semaphoreArray [nextThreadId]-> signal (); 62 // update the file to be written id63 fid = getNext (fid, false); // 64 + + count in reverse order; 65} 66} 67 68 69 int main () {70 std: cout <"hello" <std: endl; 71 72 // create thread73 std :: thread threads [MAX_THREAD]; 74 for (unsigned I = 0; I! = MAX_THREAD; ++ I) {75 threads [I] = std: thread (write, I); 76} 77 78 // join79 for (auto & thread: threads) {80 thread. join (); 81} 82 83 // output84 for (const auto & file: files) {85 std: cout <file. getName () <":" <file. getData () <std: endl; 86} 87 88 std: cout <"bye" <std: endl; 89 return 0; 90}
The Semaphore. h code can be found in: http://www.cnblogs.com/waterfall/p/7966116.html
Running result:
Code parsing: simple analysis:
This problem can also be considered as a producer and a consumer. But threads are both produced and consumed. From the file perspective, for example, the content of file A is 1 2 3 4 1 ...... It is equivalent to submitting a thread after each thread is produced.
Therefore, for each thread, set its initial file, call the wait () of its own semaphore for production, and call the signal () of the next thread after the production is complete (). Hand over the completed file to the next thread to form a flow job.
Raray:
First, this code simulates File writing with the File class to facilitate printing and debugging. The void File: write (char c) Method appends the character c at the end of the File.
According to the requirements, we can see that when A file (such as file A) is written to thread 1, it needs to be written to the next thread, namely thread 2. So there will be A: 1 2 3 4 1... B, C, D files, the same, but the initial write thread is different.
Use in code:
Unsigned currentFile [MAX_THREAD] = {0, 1, 2, 3}; // the id of the file to be written by each thread.
Specifies the file to be written to by each thread. If you do not want to configure it, you can also use threadId as the initial file id written by the thread (the one commented out in the write function). They are exactly the same.
In the code, semaphores are used to indicate the number of times a thread can write. After a file is written, the write function automatically calculates the next file to be written. The order is A, D, C, B, A..., backward.
Semaphore t1 (1), t2 (1), t3 (1), t4 (1); // used to set the Semaphore * semaphoreArray [MAX_THREAD] ={ & t1, & t2, & t3, & t4}; // put the array for convenient calling
If only the semaphores of thread 1 are set to 1, the other semaphores are set to 0. The running status of a thread can be viewed as follows:
Step 1: thread 1 semaphore 1 A-> D thread 2 semaphore 0 B blocked thread 3 semaphore 0 C blocked thread 4 semaphore 0 D blocked
Step 2: thread 1 semaphore 0 D blocked thread 2 semaphore 1 B-> A thread 3 semaphore 0 C blocked thread 4 semaphore 0 D blocked
Step 3: thread 1 semaphore 0 D blocked thread 2 semaphore 0 A blocked thread 3 semaphore 1 C-> B thread 4 semaphore 0 D blocked
Step 4: thread 1 semaphore 0 D blocked thread 2 semaphore 0 A blocked thread 3 semaphore 0 B blocked thread 4 semaphore 1 D-> C
The first round of running ends: thread 1 writes 1 to file A, thread 2 writes 2 to file B, and thread 3 writes 3 to file C, thread 4 writes 4 to file D.
The second round begins: thread 1 writes 1 to file D, thread 2 writes 2 to file ......
Similarly, only one thread is working at a time. When a thread is working, it writes characters to the file to be written and calculates the next file to be written.
In this case, there is clearly no conflict.
If you set the initial semaphore of thread 1 to 2:
Step 1: thread 1 semaphore 2 A-> D thread 2 semaphore 0 B blocked thread 3 semaphore 0 C blocked thread 4 semaphore 0 D blocked
Step 2: thread 1 semaphores 1 D-> C thread 1 semaphores 1 B-> A thread 3 semaphores 0 C blocking thread 4 semaphores 0 D Blocking
It can be seen that character 1 is written to file D, and an error occurs. The reason is that file D is expected to be written by thread 4 and is not ready before writing to file 4. At this time, it is wrong to be written by any other thread.
If the initial semaphores of thread 1 and thread 4 are respectively set to 1, and the others are set to 0. Assuming thread 4 runs first
Step1.1: thread 1 semaphore 1 A ready thread 2 semaphore 0 B blocked thread 3 semaphore 0 C blocked thread 4 semaphore 1 D-> C
Step1.2: thread 1 semaphore 2 A-> D thread 2 semaphore 0 B blocked thread 3 semaphore 0 C blocked thread 4 semaphore 0 C blocked
Step2.1: thread 1 semaphores 1 D-> C thread 1 semaphores 1 B-> A thread 3 semaphores 0 C blocking thread 4 semaphores 0 D Blocking
The file D is first written to 4 characters by thread 4, and then written to character 1 by thread 1. (The sequence of D should be 4 1 2 3 4 ......)
That is to say, the increase in the semaphore of thread 1 is based on the previous thread that has completed file writing. At this time, the file is ready and can be used by the next thread, that is, the file is passed to the next thread.
Therefore, in the final code, set the initial semaphore of each thread to 1. Can meet the requirements of the question. Even if any thread is blocked during execution (sleep simulation is available), other threads are not affected.
Assume that a long sleep is executed in thread 1. Possible running conditions:
Step 0: thread 1 semaphore 1 A ready thread 2 semaphore 1 B ready thread 3 semaphore 1 C ready thread 4 semaphore 1 D ready
After a while ......
Step 1: thread 1 semaphore 4 A ready thread 2 semaphore 0 A blocked thread 3 semaphore 0 A blocked thread 4 semaphore 0 A blocked
All threads are waiting to write data to file. However, only thread 1 writes the character 1 to file A, and then releases the signal. Then, B can continue writing the data. Followed by C and D. There is still no conflict. File A also meets the Character Sequence of 1, 2, 3, and 4.
Others:
Currently, many codes found on the internet allow only one thread to write files at a time, or write files in the next round after the end of one round by counting. This code truly implements parallel threads. Wait only when no file is writable.
Thank you.