logo

ריבוי חוטים ב-C

מבוא:

ב-C, המונח 'ריבוי חוטים' מתאר את השימוש של רבים חוטים במקביל. כל חוט עושה א משימה שונה . בשל האופי הבו-זמני של ריבוי ההליכים, משימות רבות עשויות להתבצע בבת אחת. בנוסף, ריבוי השחלות מפחית את השימוש במשאבים של המעבד . ישנן שתי קטגוריות של ריבוי משימות: מבוסס תהליכים ו מבוסס חוט . כאשר משהו מתואר כריבוי שרשורים, זה מסמל שלפחות שני שרשורים או אולי יותר פועלים באותו תהליך בבת אחת. עלינו להבין תחילה מה הם חוט ותהליך כדי להבין ריבוי-שרשורים ב-C. הבה נסתכל על נושאים אלה כדי לקבל הבנה טובה יותר.

מערך ג'אווה מחרוזת

מהם תהליכים וחוטים?

א פְּתִיל האם ה בניין יסוד לַחסוֹם של ביצוע כל תהליך. תוכנית מורכבת מכמה תהליכים, וכל תהליך מורכב מחוטים שהם יחידות הרבה יותר בסיסיות. לכן, החוט יכול להיחשב לאבן הבניין הבסיסית של תהליך או ליחידה הפשוטה יותר הקובעת במשותף את ניצול ה-CPU.

הפריטים הבאים כלולים בשרשור:

מזהה שרשור:

זה מיוחד מזהה שרשור שנוצר בזמן היווצרות החוט ונשמר למשך כל החוט הספציפי.

מונה תוכנית:

זה ערך שה עומסי חומרה .

סט רשום:

זה אוסף של רישום משותף .

ערימה:

זה שריד מזה חוט ספציפי .

בנוסף, אם שני שרשורים פועלים בו-זמנית באותו תהליך, הם משתפים קוד , קטעי נתונים , ומשאבים אחרים של מערכת הפעלה כמו קובץ נפתח ו אותות . תהליך בעל משקל כבד, סוג של תהליך קונבנציונלי, יכול לשלוט בחוט אחד. עם זאת, לריבוי חוטי שליטה יש את היכולת לפתוח ולבצע מספר משימות במקביל. המערכת הופכת יעילה משמעותית כתוצאה משימוש בחוטים, וזו הסיבה שהם שימושיים.

ההבחנה בין יחיד ו ריבוי השחלות ב-C מוסבר. קודם כל, זה א תהליך חד חוטי . כתוצאה מכך, כל הבלוק, כולל ה קוד, נתונים, וכו' - נחשב לתהליך אחד, ולתהליך זה יש רק חוט אחד. זה מסמל שהטכניקה הזו תשלים רק משימה אחת בכל פעם. אבל יש א תהליך ריבוי השחלות שעומד בניגוד לכך. יש פעילויות כמו קוד, מחסנית, נתונים , ו קבצים גם כן, אבל הם מבוצעים על ידי מספר שרשורים, שלכל אחד מהם יש מחסנית ורגיסטרים משלו. בהתחשב בכך שניתן להשלים משימות רבות בבת אחת במצב זה, התהליך ידוע בשם א תהליך ריבוי השחלות .

החוט מגיע בשני סוגים:

שרשור ברמת המשתמש:

תכנות struct array c

זה ברמת המשתמש, כפי שהשם מרמז. הליבה לא מקבלת גישה לנתונים שלו.

שרשור ברמת הקרנל

סוג השרשור מתייחס לקשר של השרשור לקרנל ולמערכת ההפעלה של המערכת.

תהליך- ניתן להתייחס לסדרת הצעדים שננקטו כדי לבצע תוכנית תהליך . תוכנית לא מופעלת מיד כשהיא מופעלת. זה מחולק לכמה שלבים בסיסיים שמתבצעים ברצף בצורה מאורגנת כדי להוביל בסופו של דבר לביצוע תהליך.

תהליך שפורק לשלבים קטנים יותר מכונה א 'תהליך שיבוט או ילד', בעוד התהליך המקורי מכונה תהליך 'הורה' . בזיכרון, כל תהליך משתמש בכמות מסוימת של שטח שאינו משותף לשום תהליכים אחרים.

הליך עובר כמה שלבים לפני הביצוע.

חָדָשׁ-

במצב זה, תהליך חדש הוא נוצר .

מוּכָן-

כאשר תהליך מוכן ומחכה להקצאת מעבד, הוא נמצא במצב זה.

רץ-

כאשר התהליך פעיל, זוהי המדינה.

הַמתָנָה-

כאשר תהליך נמצא במצב הזה, משהו כן הַמתָנָה לקרות.

הסתיים-

זהו המצב שבו מתבצע ההליך.

למה C הוא מרובה הליכי?

ריבוי השחלות ברעיון C ניתן למנף באמצעות מקביליות כדי לשפר את הפונקציונליות של האפליקציה . שקול את המקרה שבו יש לך מספר כרטיסיות פתוחות בחלון דפדפן. לאחר מכן, כל כרטיסייה פועלת במקביל ועשויה להיקרא א פְּתִיל . בהנחה שאנו משתמשים Microsoft Excel , שרשור אחד יסתדר עיצוב טקסט , וחוט אחד יהיה לטפל בקלט . לכן, תכונת ריבוי ההליכים של C מקלה על ביצוע משימות מרובות בו-זמנית. יצירת חוט מהירה משמעותית. העברת ההקשר בין שרשורים מתרחשת מהר יותר. בנוסף, ניתן ליצור תקשורת בין שרשורים מהר יותר, וסיום השרשור הוא פשוט.

10 אחוז מ-60

כיצד לכתוב תוכניות C לריבוי הליכי שרשור?

למרות שיישומי ריבוי השרשורים אינם מובנים בשפת C, זה אפשרי בהתאם למערכת ההפעלה. ה ספריית threads.h סטנדרטית משמש ליישום רעיון ריבוי ההליכים ב ג . עם זאת, אין כרגע מהדר שיכול לעשות זאת. עלינו להשתמש ביישומים ספציפיים לפלטפורמה, כגון 'POSIX' ספריית threads, באמצעות קובץ הכותרת pthread.h , אם ברצוננו להשתמש ב-multithreading ב-C. 'חוטים' זה שם אחר לזה. א POSIX ניתן ליצור חוט בדרכים הבאות:

 #include pthread_create (thread, attr, start_routine, arg) 

במקרה הזה, Pthread_create יוצר שרשור חדש כדי להפוך את השרשור לניתן להפעלה. זה מאפשר לך ליישם ריבוי פתילים ב-C כמה פעמים שתרצה בקוד שלך. הפרמטרים והתיאורים שלהם מקודמים מפורטים כאן.

פְּתִיל:

זה זיהוי יחיד ש תת-תהליך חוזר .

attr:

כאשר אנו רוצים להגדיר תכונות שרשור, אנו משתמשים בזה תכונה אטומה .

start_routine:

מתי start_routine נוצר, השרשור יפעיל שגרה.

arg:

הפרמטר שה start_routine מקבל. ריק ישמש אם לא יינתנו טיעונים.

דוגמאות מסוימות לריבוי הליכי C

להלן כמה דוגמאות לבעיות ריבוי פתילים ב-C.

1. סוגיית הקורא-כותב

בעיה נפוצה של מערכת הפעלה עם סנכרון תהליכים היא בעיית קורא/כותב . נניח שיש לנו מסד נתונים זה קוראים ו סופרים , שתי קטגוריות משתמש שונות, יכול לגשת. קוראים הם היחידים שיכולים לקרוא מסד הנתונים, ואילו סופרים הם היחידים שיכולים לקרוא את מסד הנתונים ולעדכן גם אותו. בואו נשתמש IRCTC כדוגמה פשוטה. אם ברצוננו לבדוק את המצב של ספציפי מספר רכבת , פשוט הזן את מספר הרכבת למערכת כדי להציג את מידע הרכבת הרלוונטי. רק המידע הקיים באתר מוצג כאן. אופרטור הקריאה הוא זה. עם זאת, אם ברצוננו להזמין כרטיס, עלינו למלא את טופס הזמנת הכרטיס עם פרטים כמו שמנו, גילנו וכדומה. אז, נבצע פעולת כתיבה כאן. יהיו כמה התאמות ל- מסד נתונים של IRCTC .

הבעיה היא שכמה אנשים מנסים בו זמנית לגשת ל- מסד נתונים של IRCTC . הם עשויים להיות א סוֹפֵר או א קוֹרֵא . הבעיה מתעוררת אם קורא כבר משתמש במסד הנתונים וכותב ניגש אליו בו זמנית כדי לעבוד על אותם נתונים. בעיה נוספת מתעוררת כאשר כותב משתמש במסד נתונים, וקורא ניגש לאותו מידע כמו מסד הנתונים. שלישית, קיים קושי כאשר כותב אחד מעדכן את מסד הנתונים בעוד אחר מנסה לעדכן נתונים באותו מסד נתונים. התרחיש הרביעי מתרחש כאשר שני קוראים מנסים לאחזר את אותו החומר. כל הבעיות הללו מתעוררות אם הקורא והכותב משתמשים באותם נתוני מסד נתונים.

סמפור היא שיטה המשמשת כדי לפתור בעיה זו. בואו נסתכל על המחשה כיצד להשתמש בבעיה זו.

תהליך הקורא:

 #include #include #include int rc = 0; // Reader count int data = 0; // Shared data pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_twrt = PTHREAD_COND_INITIALIZER; void* reader(void* arg) { int reader_id = *(int*)arg; pthread_mutex_lock(&mutex); rc++; if (rc == 1) pthread_cond_wait(&wrt, &mutex); pthread_mutex_unlock(&mutex); // Reading the shared data printf('Reader %d reads data: %d
&apos;, reader_id, data); pthread_mutex_lock(&amp;mutex); rc--; if (rc == 0) pthread_cond_signal(&amp;wrt); pthread_mutex_unlock(&amp;mutex); return NULL; } int main() { pthread_treaders[5]; // Assuming 5 reader threads int reader_ids[5]; for (int i = 0; i<5; i++) { reader_ids[i]="i" + 1; pthread_create(&readers[i], null, reader, &reader_ids[i]); } joining reader threads for (int i="0;" i< 5; pthread_join(readers[i], null); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Reader 1 reads data: 0 Reader 2 reads data: 0 Reader 3 reads data: 0 Reader 4 reads data: 0 Reader 5 reads data: 0 </pre> <p> <strong>Explanation:</strong> </p> <p>In this code, we have the shared variable data and the <strong> <em>reader count rc</em> </strong> . The <strong> <em>wrt condition</em> </strong> variable is used to limit access for the <strong> <em>writer process</em> </strong> , and the <strong> <em>mutex</em> </strong> is used to guarantee mutual exclusion for accessing the shared data.</p> <p>The reader process is represented by the <strong> <em>reader() function</em> </strong> . The <strong> <em>reader count (rc)</em> </strong> is increased before attaining the <strong> <em>mutex lock</em> </strong> . It uses <strong> <em>pthread_cond_wait()</em> </strong> to wait on the <strong> <em>wrt condition</em> </strong> variable if it is the <strong> <em>first reader (rc == 1)</em> </strong> . As a result, writers will be prevented from writing until all readers have completed.</p> <p>The reader process checks if it was the <strong> <em>last reader (rc == 0)</em> </strong> and lowers the reader <strong> <em>count (rc--)</em> </strong> after reading the shared data. If it was, <strong> <em>pthread_cond_signal()</em> </strong> signals the <strong> <em>wrt condition</em> </strong> variable to let waiting writer processes continue.</p> <p>Using the <strong> <em>pthread_create()</em> </strong> and <strong> <em>pthread_join() functions</em> </strong> , we <strong> <em>new</em> </strong> and <strong> <em>join</em> </strong> multiple reader threads in the <strong> <em>main() function</em> </strong> . An individual ID is assigned to each reader thread for identifying purposes.</p> <h3>Writer process:</h3> <pre> wait(wrt); . . WRITE INTO THE OBJECT . signal(wrt); </pre> <p>In the above example, same as the <strong> <em>reader process</em> </strong> , an operation known as the wait operation is carried out on <strong> <em>&apos;wrt&apos;</em> </strong> when a user wishes to access the data or object. After that, the new user won&apos;t be able to access the object. And once the user has finished writing, another signal operation is performed on <strong> <em>wrt</em> </strong> .</p> <h3>2. lock and unlock problem:</h3> <p>The idea of a <strong> <em>mutex</em> </strong> is utilized in multithreading in C to guarantee that there won&apos;t be a <strong> <em>race condition</em> </strong> between the <strong> <em>threads</em> </strong> . When multiple threads begin processing the same data at once, this circumstance is known as <strong> <em>racing</em> </strong> . However, if these circumstances exist, we must. We use the <strong> <em>mutex&apos;s lock()</em> </strong> and <strong> <em>unlock() functions</em> </strong> to secure a particular section of code for a specific thread. Such that, another thread cannot begin performing the same operation. The <strong> <em>&apos;critical section/region&apos;</em> </strong> is the name given to this protected code area. Before using the shared resources, we set up a lot in a certain area, and once we&apos;ve finished using them, we unlock them once more.</p> <p>Let&apos;s examine the operation of the mutex for locking and unlocking in multithreading in C:</p> <p> <strong>Example:</strong> </p> <pre> #include #include #include pthread_mutex_tmy_mutex = PTHREAD_MUTEX_INITIALIZER; int shared_data = 0; void *thread_function(void *arg) { pthread_mutex_lock(&amp;my_mutex); shared_data++; // Modify the shared data printf(&apos;Thread %ld: Shared data modified. New value: %d
&apos;, (long)arg, shared_data); pthread_mutex_unlock(&amp;my_mutex); return NULL; } int main() { pthread_tthreads[5]; // Assuming 5 threads for (int i = 0; i<5; i++) { if (pthread_create(&threads[i], null, thread_function, (void *)(long)(i + 1)) !="0)" fprintf(stderr, 'error creating thread %d
', i 1); return 1; } for (int i< 5; (pthread_join(threads[i], null) joining 0; < pre> <p> <strong>Output:</strong> </p> <pre> Thread 1: Shared data modified. New value: 1 Thread 2: Shared data modified. New value: 2 Thread 3: Shared data modified. New value: 3 Thread 4: Shared data modified. New value: 4 Thread 5: Shared data modified. New value: 5 </pre> <p> <strong>Explanation:</strong> </p> <p>In this above example, we explain how we <strong> <em>lock</em> </strong> and <strong> <em>unlock</em> </strong> a certain region of code that shields us from the racing situation. <strong> <em>&apos;pthread_mutex_t&apos;</em> </strong> is used as an <strong> <em>initializer</em> </strong> in the example above. <strong> <em>&apos;pthread_mutex_lock&apos;</em> </strong> is then <strong> <em>written</em> </strong> before the beginning of the code that we want to lock. The coding that we wish to lock is finished after that. After that, the locking of the code is terminated using <strong> <em>&apos;pthread_mutex_unlock&apos;</em> </strong> ; going forward, no code will be in lock mode.</p> <h2>The Dining Philosopher Problem:</h2> <p>One of the classic issues with synchronization is the <strong> <em>dining philosopher issue</em> </strong> . Simple resource allocation for several processes is required but shouldn&apos;t result in a <strong> <em>stalemate</em> </strong> or <strong> <em>hunger</em> </strong> . The <strong> <em>dining philosopher problem</em> </strong> can be viewed as a straightforward representation of a number of processes, each of which is demanding resources. Since each of these processes requires a resource allocation, it is necessary to distribute those resources across all of the processes so that no one process ever gets stuck or stops working.</p> <p>Assume there are five philosophers seated at a <strong> <em>circle-shaped table</em> </strong> . They eat at one point and ponder about something at another. Around the round table, the philosophers are evenly spaced out on the chairs. Additionally, there is a bowl of rice and five chopsticks for each philosopher in the middle of the table. When the philosopher feels she cannot interact with her colleagues who are seated nearby.</p> <p>A philosopher occasionally takes up two chopsticks when she becomes hungry. She chooses two chopsticks from her neighbors-one on her <strong> <em>left</em> </strong> and one on her <strong> <em>right</em> </strong> -that are within easy reach. But the philosopher should never pick up more than one chopstick at once. She will obviously be unable to pick up the chopstick that the neighbor is using.</p> <p> <strong>Example:</strong> </p> <p>Let&apos;s use an example to demonstrate how this is implemented in C.</p> <pre> #include #include #include #include #include pthread_tphilosopher[5]; pthread_mutex_tchopstick[5]; void *func(void *arg) { int n = *(int *)arg; printf(&apos;
Philosopher %d is thinking.&apos;, n); pthread_mutex_lock(&amp;chopstick[n]); pthread_mutex_lock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d is eating.&apos;, n); sleep(3); pthread_mutex_unlock(&amp;chopstick[n]); pthread_mutex_unlock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d Finished eating &apos;, n); return NULL; } int main() { int i, k; void *message; for (i = 0; i<5; i++) { k="pthread_mutex_init(&amp;chopstick[i]," null); if (k !="0)" printf('failed to initialize the mutex
'); exit(1); } for (i="0;" i< 5; null, func, (void *)&i); printf('error in thread creation.
'); &message); join thread.
'); printf('mutex destroyed.
'); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Philosopher 0 is thinking. Philosopher 1 is thinking. Philosopher 2 is thinking. Philosopher 3 is thinking. Philosopher 4 is thinking. Philosopher 0 is eating. Philosopher 1 is eating. Philosopher 2 is eating. Philosopher 3 is eating. Philosopher 4 is eating. Philosopher 0 Finished eating Philosopher 1 Finished eating Philosopher 2 Finished eating Philosopher 3 Finished eating Philosopher 4 Finished eating </pre> <p> <strong>Explanation:</strong> </p> <p> <strong> <em>Chopsticks</em> </strong> can be represented by a semaphore. Since there are <strong> <em>chopsticks</em> </strong> on the table and no philosopher has chosen one, all of the chopsticks&apos; components are first initialized to <strong> <em>1</em> </strong> . Now that <strong> <em>chopstick[i]</em> </strong> has been chosen as the first <strong> <em>chopstick. chopstick[i]</em> </strong> and <strong> <em>chopstick[(i+1)%5]</em> </strong> are subject to the first wait operation. These <strong> <em>chopsticks&apos; wait operation</em> </strong> indicates that the philosopher has picked them up. The eating process begins once the philosopher selects his <strong> <em>chopstick</em> </strong> . The signal operation is now carried out on the <strong> <em>chopsticks [i]</em> </strong> and <strong> <em>[(i+1)%5]</em> </strong> once the philosopher has finished eating. The philosopher then turns back to sleep.</p> <p>To determine whether the <strong> <em>subthread</em> </strong> has joined the main thread or not, we used the <strong> <em>pthread_join function</em> </strong> . Similarly, we have checked whether the <strong> <em>mutex</em> </strong> lock has been initialized using the <strong> <em>pthread_mutex_init</em> </strong> method.</p> <p>To initialize and verify whether the new thread was created or not, we utilized the <strong> <em>pthread_create function</em> </strong> . Similar to this, we destroyed the <strong> <em>mutex lock</em> </strong> using the <strong> <em>pthread_mutex_destroy</em> </strong> function.</p> <h2>The Producer-Consumer Problem:</h2> <p>A common issue with multithreading process synchronization is the <strong> <em>producer-consumer problem</em> </strong> . Two processes are present in it: the first is the <strong> <em>producer&apos;s process</em> </strong> , and the second is the <strong> <em>consumer&apos;s process</em> </strong> . Furthermore, it is assumed that both operations are occurring concurrently in parallel. Additionally, they are a cooperative process, which implies that they are sharing something with one another. It is important that when the buffer is <strong> <em>full</em> </strong> , the producer cannot add data. When the buffer is empty, the consumer cannot extract data from the buffer because the common buffer size between the producer and the consumer is <strong> <em>fixed</em> </strong> . The issue is stated in this way. Hence, to implement the Producer-Consumer problem and solve it, we shall employ the idea of parallel programming.</p> <p> <strong>Example:</strong> </p> <pre> #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } </pre> <p> <strong>Output:</strong> </p> <pre> 1. producer 2. consumer 3. for exit Please enter your choice: </pre> <p> <strong>Explanation:</strong> </p> <p>We perform two tasks. The functions <strong> <em>consumer()</em> </strong> and <strong> <em>producer()</em> </strong> indicate the status and operation of the <strong> <em>consumer</em> </strong> and <strong> <em>producer</em> </strong> . The <strong> <em>producer() method</em> </strong> will create the <strong> <em>mutex lock</em> </strong> and determine whether the buffer is <strong> <em>full</em> </strong> when it is called. When the buffer is full, nothing will be produced. If not, it will <strong> <em>create</em> </strong> , and then, after the <strong> <em>production</em> </strong> , it will put itself to sleep to unlock the <strong> <em>mutex lock</em> </strong> . Like the <strong> <em>producer</em> </strong> , the consumer first creates the <strong> <em>mutex lock</em> </strong> , checks the <strong> <em>buffer</em> </strong> , consumes the <strong> <em>product</em> </strong> , and then releases the lock before going back to sleep.</p> <p>A <strong> <em>counter (x)</em> </strong> will be used during manufacturing and will keep growing until the manufacturer produces the item. However, the consumer will make fewer of the same manufactured <strong> <em>item (x)</em> </strong> .</p> <h2>Conclusion:</h2> <p>The idea of using <strong> <em>two</em> </strong> or <strong> <em>more threads</em> </strong> to execute a program is known as <strong> <em>multithreading</em> </strong> in the C programming language. <strong> <em>Multithreading</em> </strong> allows for the simultaneous execution of several tasks. The simplest executable component of a program is a <strong> <em>thread</em> </strong> . The process is the idea that a task can be completed by breaking it up into several smaller <strong> <em>sub-processes</em> </strong> .</p> <p>The header file <strong> <em>pthread.h</em> </strong> is required in order to implement multithreading in C since it cannot be done directly.</p> <hr></5;></pre></5;></pre></5;>

הֶסבֵּר:

בקוד זה, יש לנו את הנתונים המשתנים המשותפים ואת ספירת קוראים rc . ה מצב wrt המשתנה משמש להגבלת גישה עבור תהליך סופר , וה מנעול משמש כדי להבטיח אי הכללה הדדית עבור גישה לנתונים המשותפים.

תהליך הקורא מיוצג על ידי ה פונקציית reader(). . ה ספירת קוראים (rc) גדל לפני השגת נעילת mutex . זה משתמש pthread_cond_wait() לחכות על מצב wrt משתנה אם זה ה קורא ראשון (rc == 1) . כתוצאה מכך, סופרים יימנעו מלכתוב עד שכל הקוראים יסיימו.

תהליך הקורא בודק אם זה היה הקורא האחרון (rc == 0) ומוריד את הקורא ספירה (rc--) לאחר קריאת הנתונים המשותפים. אם זה היה, pthread_cond_signal() מסמן את מצב wrt משתנה כדי לאפשר לתהליכי כותב המתנה להמשיך.

משתמש ב pthread_create() ו פונקציות pthread_join(). , אנחנו חָדָשׁ ו לְהִצְטַרֵף שרשורי קוראים מרובים ב- הפונקציה main(). . זיהוי אישי מוקצה לכל שרשור קורא למטרות זיהוי.

תהליך הכתיבה:

 wait(wrt); . . WRITE INTO THE OBJECT . signal(wrt); 

בדוגמה לעיל, זהה ל- תהליך הקורא , מתבצעת פעולה המכונה פעולת ההמתנה 'כתוב' כאשר משתמש מעוניין לגשת לנתונים או לאובייקט. לאחר מכן, המשתמש החדש לא יוכל לגשת לאובייקט. וברגע שהמשתמש סיים לכתוב, מבוצעת פעולת אות נוספת על wrt .

2. בעיית נעילה וביטול נעילה:

הרעיון של א מנעול משמש בריבוי השחלות ב-C כדי להבטיח שלא יהיה א מצב Race בין ה חוטים . כאשר שרשורים מרובים מתחילים לעבד את אותם נתונים בבת אחת, תופעה זו ידועה בשם מירוץ . עם זאת, אם נסיבות אלה מתקיימות, עלינו. אנו משתמשים ב- הנעילה של mutex() ו unlock() פונקציות כדי לאבטח קטע קוד מסוים עבור שרשור ספציפי. כך שרשור אחר לא יכול להתחיל לבצע את אותה פעולה. ה 'קטע/אזור קריטי' הוא השם שניתן לאזור הקוד המוגן הזה. לפני השימוש במשאבים המשותפים, הגדרנו הרבה באזור מסוים, ולאחר שסיימנו להשתמש בהם, אנו פותחים אותם פעם נוספת.

הבה נבחן את פעולת המוטקס לנעילה ופתיחה ב-multithreading ב-C:

דוגמא:

 #include #include #include pthread_mutex_tmy_mutex = PTHREAD_MUTEX_INITIALIZER; int shared_data = 0; void *thread_function(void *arg) { pthread_mutex_lock(&amp;my_mutex); shared_data++; // Modify the shared data printf(&apos;Thread %ld: Shared data modified. New value: %d
&apos;, (long)arg, shared_data); pthread_mutex_unlock(&amp;my_mutex); return NULL; } int main() { pthread_tthreads[5]; // Assuming 5 threads for (int i = 0; i<5; i++) { if (pthread_create(&threads[i], null, thread_function, (void *)(long)(i + 1)) !="0)" fprintf(stderr, \'error creating thread %d
\', i 1); return 1; } for (int i< 5; (pthread_join(threads[i], null) joining 0; < pre> <p> <strong>Output:</strong> </p> <pre> Thread 1: Shared data modified. New value: 1 Thread 2: Shared data modified. New value: 2 Thread 3: Shared data modified. New value: 3 Thread 4: Shared data modified. New value: 4 Thread 5: Shared data modified. New value: 5 </pre> <p> <strong>Explanation:</strong> </p> <p>In this above example, we explain how we <strong> <em>lock</em> </strong> and <strong> <em>unlock</em> </strong> a certain region of code that shields us from the racing situation. <strong> <em>&apos;pthread_mutex_t&apos;</em> </strong> is used as an <strong> <em>initializer</em> </strong> in the example above. <strong> <em>&apos;pthread_mutex_lock&apos;</em> </strong> is then <strong> <em>written</em> </strong> before the beginning of the code that we want to lock. The coding that we wish to lock is finished after that. After that, the locking of the code is terminated using <strong> <em>&apos;pthread_mutex_unlock&apos;</em> </strong> ; going forward, no code will be in lock mode.</p> <h2>The Dining Philosopher Problem:</h2> <p>One of the classic issues with synchronization is the <strong> <em>dining philosopher issue</em> </strong> . Simple resource allocation for several processes is required but shouldn&apos;t result in a <strong> <em>stalemate</em> </strong> or <strong> <em>hunger</em> </strong> . The <strong> <em>dining philosopher problem</em> </strong> can be viewed as a straightforward representation of a number of processes, each of which is demanding resources. Since each of these processes requires a resource allocation, it is necessary to distribute those resources across all of the processes so that no one process ever gets stuck or stops working.</p> <p>Assume there are five philosophers seated at a <strong> <em>circle-shaped table</em> </strong> . They eat at one point and ponder about something at another. Around the round table, the philosophers are evenly spaced out on the chairs. Additionally, there is a bowl of rice and five chopsticks for each philosopher in the middle of the table. When the philosopher feels she cannot interact with her colleagues who are seated nearby.</p> <p>A philosopher occasionally takes up two chopsticks when she becomes hungry. She chooses two chopsticks from her neighbors-one on her <strong> <em>left</em> </strong> and one on her <strong> <em>right</em> </strong> -that are within easy reach. But the philosopher should never pick up more than one chopstick at once. She will obviously be unable to pick up the chopstick that the neighbor is using.</p> <p> <strong>Example:</strong> </p> <p>Let&apos;s use an example to demonstrate how this is implemented in C.</p> <pre> #include #include #include #include #include pthread_tphilosopher[5]; pthread_mutex_tchopstick[5]; void *func(void *arg) { int n = *(int *)arg; printf(&apos;
Philosopher %d is thinking.&apos;, n); pthread_mutex_lock(&amp;chopstick[n]); pthread_mutex_lock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d is eating.&apos;, n); sleep(3); pthread_mutex_unlock(&amp;chopstick[n]); pthread_mutex_unlock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d Finished eating &apos;, n); return NULL; } int main() { int i, k; void *message; for (i = 0; i<5; i++) { k="pthread_mutex_init(&amp;chopstick[i]," null); if (k !="0)" printf(\'failed to initialize the mutex
\'); exit(1); } for (i="0;" i< 5; null, func, (void *)&i); printf(\'error in thread creation.
\'); &message); join thread.
\'); printf(\'mutex destroyed.
\'); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Philosopher 0 is thinking. Philosopher 1 is thinking. Philosopher 2 is thinking. Philosopher 3 is thinking. Philosopher 4 is thinking. Philosopher 0 is eating. Philosopher 1 is eating. Philosopher 2 is eating. Philosopher 3 is eating. Philosopher 4 is eating. Philosopher 0 Finished eating Philosopher 1 Finished eating Philosopher 2 Finished eating Philosopher 3 Finished eating Philosopher 4 Finished eating </pre> <p> <strong>Explanation:</strong> </p> <p> <strong> <em>Chopsticks</em> </strong> can be represented by a semaphore. Since there are <strong> <em>chopsticks</em> </strong> on the table and no philosopher has chosen one, all of the chopsticks&apos; components are first initialized to <strong> <em>1</em> </strong> . Now that <strong> <em>chopstick[i]</em> </strong> has been chosen as the first <strong> <em>chopstick. chopstick[i]</em> </strong> and <strong> <em>chopstick[(i+1)%5]</em> </strong> are subject to the first wait operation. These <strong> <em>chopsticks&apos; wait operation</em> </strong> indicates that the philosopher has picked them up. The eating process begins once the philosopher selects his <strong> <em>chopstick</em> </strong> . The signal operation is now carried out on the <strong> <em>chopsticks [i]</em> </strong> and <strong> <em>[(i+1)%5]</em> </strong> once the philosopher has finished eating. The philosopher then turns back to sleep.</p> <p>To determine whether the <strong> <em>subthread</em> </strong> has joined the main thread or not, we used the <strong> <em>pthread_join function</em> </strong> . Similarly, we have checked whether the <strong> <em>mutex</em> </strong> lock has been initialized using the <strong> <em>pthread_mutex_init</em> </strong> method.</p> <p>To initialize and verify whether the new thread was created or not, we utilized the <strong> <em>pthread_create function</em> </strong> . Similar to this, we destroyed the <strong> <em>mutex lock</em> </strong> using the <strong> <em>pthread_mutex_destroy</em> </strong> function.</p> <h2>The Producer-Consumer Problem:</h2> <p>A common issue with multithreading process synchronization is the <strong> <em>producer-consumer problem</em> </strong> . Two processes are present in it: the first is the <strong> <em>producer&apos;s process</em> </strong> , and the second is the <strong> <em>consumer&apos;s process</em> </strong> . Furthermore, it is assumed that both operations are occurring concurrently in parallel. Additionally, they are a cooperative process, which implies that they are sharing something with one another. It is important that when the buffer is <strong> <em>full</em> </strong> , the producer cannot add data. When the buffer is empty, the consumer cannot extract data from the buffer because the common buffer size between the producer and the consumer is <strong> <em>fixed</em> </strong> . The issue is stated in this way. Hence, to implement the Producer-Consumer problem and solve it, we shall employ the idea of parallel programming.</p> <p> <strong>Example:</strong> </p> <pre> #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } </pre> <p> <strong>Output:</strong> </p> <pre> 1. producer 2. consumer 3. for exit Please enter your choice: </pre> <p> <strong>Explanation:</strong> </p> <p>We perform two tasks. The functions <strong> <em>consumer()</em> </strong> and <strong> <em>producer()</em> </strong> indicate the status and operation of the <strong> <em>consumer</em> </strong> and <strong> <em>producer</em> </strong> . The <strong> <em>producer() method</em> </strong> will create the <strong> <em>mutex lock</em> </strong> and determine whether the buffer is <strong> <em>full</em> </strong> when it is called. When the buffer is full, nothing will be produced. If not, it will <strong> <em>create</em> </strong> , and then, after the <strong> <em>production</em> </strong> , it will put itself to sleep to unlock the <strong> <em>mutex lock</em> </strong> . Like the <strong> <em>producer</em> </strong> , the consumer first creates the <strong> <em>mutex lock</em> </strong> , checks the <strong> <em>buffer</em> </strong> , consumes the <strong> <em>product</em> </strong> , and then releases the lock before going back to sleep.</p> <p>A <strong> <em>counter (x)</em> </strong> will be used during manufacturing and will keep growing until the manufacturer produces the item. However, the consumer will make fewer of the same manufactured <strong> <em>item (x)</em> </strong> .</p> <h2>Conclusion:</h2> <p>The idea of using <strong> <em>two</em> </strong> or <strong> <em>more threads</em> </strong> to execute a program is known as <strong> <em>multithreading</em> </strong> in the C programming language. <strong> <em>Multithreading</em> </strong> allows for the simultaneous execution of several tasks. The simplest executable component of a program is a <strong> <em>thread</em> </strong> . The process is the idea that a task can be completed by breaking it up into several smaller <strong> <em>sub-processes</em> </strong> .</p> <p>The header file <strong> <em>pthread.h</em> </strong> is required in order to implement multithreading in C since it cannot be done directly.</p> <hr></5;></pre></5;>

הֶסבֵּר:

כיצד למחוק עמודה ב-postgresql

בדוגמה זו לעיל, אנו מסבירים כיצד אנו לנעול ו לבטל נעילה אזור מסוים של קוד שמגן עלינו ממצב המירוצים. 'pthread_mutex_t' משמש בתור an אתחול בדוגמה למעלה. 'pthread_mutex_lock' הוא אז כתוב לפני תחילת הקוד שאנו רוצים לנעול. הקידוד שברצוננו לנעול מסתיים לאחר מכן. לאחר מכן, נעילת הקוד מסתיימת באמצעות 'pthread_mutex_unlock' ; בהמשך, שום קוד לא יהיה במצב נעילה.

בעיית פילוסוף האוכל:

אחת הבעיות הקלאסיות עם סנכרון היא סוגיית פילוסוף אוכל . הקצאת משאבים פשוטה עבור מספר תהליכים נדרשת אך לא אמורה לגרום ל- מָבוֹי סָתוּם אוֹ רעב . ה בעיית פילוסוף האוכל ניתן לראות כייצוג פשוט של מספר תהליכים, שכל אחד מהם דורש משאבים. מכיוון שכל אחד מהתהליכים הללו דורש הקצאת משאבים, יש צורך להפיץ את המשאבים הללו על פני כל התהליכים כך שאף תהליך אף פעם לא יתקע או יפסיק לעבוד.

נניח שיש חמישה פילוסופים שיושבים ב-a שולחן בצורת עיגול . הם אוכלים בשלב מסוים ומתלבטים במשהו בשלב אחר. מסביב לשולחן העגול, הפילוסופים מפוזרים באופן שווה על הכיסאות. בנוסף, יש קערת אורז וחמישה מקלות אכילה לכל פילוסוף באמצע השולחן. כשהפילוסוף מרגישה שהיא לא יכולה לקיים אינטראקציה עם עמיתיה שיושבים בקרבת מקום.

פילוסוף לוקח מדי פעם שני מקלות אכילה כשהיא נעשית רעבה. היא בוחרת שני מקלות אכילה מהשכנים שלה - אחד עליה שמאלה ואחד עליה ימין -שנמצאים בהישג יד. אבל הפילוסוף לא צריך להרים יותר ממקל אכילה אחד בבת אחת. ברור שהיא לא תוכל להרים את הצ'ופצ'יק שהשכן משתמש בו.

דוגמא:

בואו נשתמש בדוגמה כדי להדגים כיצד זה מיושם ב-C.

 #include #include #include #include #include pthread_tphilosopher[5]; pthread_mutex_tchopstick[5]; void *func(void *arg) { int n = *(int *)arg; printf(&apos;
Philosopher %d is thinking.&apos;, n); pthread_mutex_lock(&amp;chopstick[n]); pthread_mutex_lock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d is eating.&apos;, n); sleep(3); pthread_mutex_unlock(&amp;chopstick[n]); pthread_mutex_unlock(&amp;chopstick[(n + 1) % 5]); printf(&apos;
Philosopher %d Finished eating &apos;, n); return NULL; } int main() { int i, k; void *message; for (i = 0; i<5; i++) { k="pthread_mutex_init(&amp;chopstick[i]," null); if (k !="0)" printf(\'failed to initialize the mutex
\'); exit(1); } for (i="0;" i< 5; null, func, (void *)&i); printf(\'error in thread creation.
\'); &message); join thread.
\'); printf(\'mutex destroyed.
\'); return 0; < pre> <p> <strong>Output:</strong> </p> <pre> Philosopher 0 is thinking. Philosopher 1 is thinking. Philosopher 2 is thinking. Philosopher 3 is thinking. Philosopher 4 is thinking. Philosopher 0 is eating. Philosopher 1 is eating. Philosopher 2 is eating. Philosopher 3 is eating. Philosopher 4 is eating. Philosopher 0 Finished eating Philosopher 1 Finished eating Philosopher 2 Finished eating Philosopher 3 Finished eating Philosopher 4 Finished eating </pre> <p> <strong>Explanation:</strong> </p> <p> <strong> <em>Chopsticks</em> </strong> can be represented by a semaphore. Since there are <strong> <em>chopsticks</em> </strong> on the table and no philosopher has chosen one, all of the chopsticks&apos; components are first initialized to <strong> <em>1</em> </strong> . Now that <strong> <em>chopstick[i]</em> </strong> has been chosen as the first <strong> <em>chopstick. chopstick[i]</em> </strong> and <strong> <em>chopstick[(i+1)%5]</em> </strong> are subject to the first wait operation. These <strong> <em>chopsticks&apos; wait operation</em> </strong> indicates that the philosopher has picked them up. The eating process begins once the philosopher selects his <strong> <em>chopstick</em> </strong> . The signal operation is now carried out on the <strong> <em>chopsticks [i]</em> </strong> and <strong> <em>[(i+1)%5]</em> </strong> once the philosopher has finished eating. The philosopher then turns back to sleep.</p> <p>To determine whether the <strong> <em>subthread</em> </strong> has joined the main thread or not, we used the <strong> <em>pthread_join function</em> </strong> . Similarly, we have checked whether the <strong> <em>mutex</em> </strong> lock has been initialized using the <strong> <em>pthread_mutex_init</em> </strong> method.</p> <p>To initialize and verify whether the new thread was created or not, we utilized the <strong> <em>pthread_create function</em> </strong> . Similar to this, we destroyed the <strong> <em>mutex lock</em> </strong> using the <strong> <em>pthread_mutex_destroy</em> </strong> function.</p> <h2>The Producer-Consumer Problem:</h2> <p>A common issue with multithreading process synchronization is the <strong> <em>producer-consumer problem</em> </strong> . Two processes are present in it: the first is the <strong> <em>producer&apos;s process</em> </strong> , and the second is the <strong> <em>consumer&apos;s process</em> </strong> . Furthermore, it is assumed that both operations are occurring concurrently in parallel. Additionally, they are a cooperative process, which implies that they are sharing something with one another. It is important that when the buffer is <strong> <em>full</em> </strong> , the producer cannot add data. When the buffer is empty, the consumer cannot extract data from the buffer because the common buffer size between the producer and the consumer is <strong> <em>fixed</em> </strong> . The issue is stated in this way. Hence, to implement the Producer-Consumer problem and solve it, we shall employ the idea of parallel programming.</p> <p> <strong>Example:</strong> </p> <pre> #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } </pre> <p> <strong>Output:</strong> </p> <pre> 1. producer 2. consumer 3. for exit Please enter your choice: </pre> <p> <strong>Explanation:</strong> </p> <p>We perform two tasks. The functions <strong> <em>consumer()</em> </strong> and <strong> <em>producer()</em> </strong> indicate the status and operation of the <strong> <em>consumer</em> </strong> and <strong> <em>producer</em> </strong> . The <strong> <em>producer() method</em> </strong> will create the <strong> <em>mutex lock</em> </strong> and determine whether the buffer is <strong> <em>full</em> </strong> when it is called. When the buffer is full, nothing will be produced. If not, it will <strong> <em>create</em> </strong> , and then, after the <strong> <em>production</em> </strong> , it will put itself to sleep to unlock the <strong> <em>mutex lock</em> </strong> . Like the <strong> <em>producer</em> </strong> , the consumer first creates the <strong> <em>mutex lock</em> </strong> , checks the <strong> <em>buffer</em> </strong> , consumes the <strong> <em>product</em> </strong> , and then releases the lock before going back to sleep.</p> <p>A <strong> <em>counter (x)</em> </strong> will be used during manufacturing and will keep growing until the manufacturer produces the item. However, the consumer will make fewer of the same manufactured <strong> <em>item (x)</em> </strong> .</p> <h2>Conclusion:</h2> <p>The idea of using <strong> <em>two</em> </strong> or <strong> <em>more threads</em> </strong> to execute a program is known as <strong> <em>multithreading</em> </strong> in the C programming language. <strong> <em>Multithreading</em> </strong> allows for the simultaneous execution of several tasks. The simplest executable component of a program is a <strong> <em>thread</em> </strong> . The process is the idea that a task can be completed by breaking it up into several smaller <strong> <em>sub-processes</em> </strong> .</p> <p>The header file <strong> <em>pthread.h</em> </strong> is required in order to implement multithreading in C since it cannot be done directly.</p> <hr></5;>

הֶסבֵּר:

מקלות אכילה יכול להיות מיוצג על ידי סמפור. מאז שיש מקלות אכילה על השולחן ואף פילוסוף לא בחר אחד, כל רכיבי הצ'ופסטיקס מאותחלים תחילה 1 . עכשיו זה מקל אכילה[i] נבחר כראשון מקל אכילה. מקל אכילה[i] ו מקל אכילה[(i+1)%5] כפופים לפעולת ההמתנה הראשונה. אלה פעולת המתנה של מקלות אכילה מצביע על כך שהפילוסוף הרים אותם. תהליך האכילה מתחיל ברגע שהפילוסוף בוחר את שלו מקל אכילה . פעולת האות מתבצעת כעת על מקלות אכילה [i] ו [(i+1)%5] ברגע שהפילוסוף סיים לאכול. לאחר מכן הפילוסוף חוזר לישון.

כדי לקבוע אם ה שרשור משנה הצטרף לשרשור הראשי או לא, השתמשנו ב- פונקציית pthread_join . באופן דומה, בדקנו האם מנעול המנעול אותחל באמצעות pthread_mutex_init שיטה.

עידן הריטיק רושן

כדי לאתחל ולוודא אם השרשור החדש נוצר או לא, השתמשנו ב- פונקציית pthread_create . בדומה לזה, הרסנו את נעילת mutex משתמש ב pthread_mutex_destroy פוּנקצִיָה.

בעיית המפיק-צרכן:

בעיה נפוצה בסנכרון תהליכי ריבוי השחלות היא בעיה של יצרן-צרכן . שני תהליכים קיימים בו: הראשון הוא ה תהליך המפיק , והשני הוא ה תהליך הצרכן . יתר על כן, ההנחה היא ששתי הפעולות מתרחשות במקביל במקביל. בנוסף, הם תהליך שיתופי, מה שמרמז שהם חולקים משהו אחד עם השני. חשוב שכאשר החיץ הוא מלא , המפיק לא יכול להוסיף נתונים. כאשר המאגר ריק, הצרכן אינו יכול לחלץ נתונים מהמאגר מכיוון שגודל המאגר המשותף בין היצרן לצרכן הוא תוקן . הנושא מובא בצורה זו. לפיכך, כדי ליישם את בעיית המפיק-צרכן ולפתור אותה, נשתמש ברעיון של תכנות מקביל.

דוגמא:

 #include #include int mutex = 1, full = 0, empty = 3, x = 0; int main() { int n; void producer(); void consumer(); int wait(int); int signal(int); printf(&apos;
1.producer
2.consumer
3.for exit&apos;); while (1) { printf(&apos;
 Please enter your choice:&apos;); scanf(&apos;%d&apos;, &amp;n); switch (n) { case 1: if ((mutex == 1) &amp;&amp; (empty != 0)) producer(); else printf(&apos;Oops!! the buffer is full!!&apos;); break; case 2: if ((mutex == 1) &amp;&amp; (full != 0)) consumer(); else printf(&apos;Oops!! the buffer is empty!!&apos;); break; case 3: exit(0); break; } } return 0; } int wait(int s) { return (--s); } int signal(int s) { return (++s); } void producer() { mutex = wait(mutex); full = signal(full); empty = wait(empty); x++; printf(&apos;
Item produced by the Producer %d&apos;, x); mutex = signal(mutex); } void consumer() { mutex = wait(mutex); full = wait(full); empty = signal(empty); printf(&apos;
Item consumed by the Consumer %d&apos;, x); x--; mutex = signal(mutex); } 

תְפוּקָה:

 1. producer 2. consumer 3. for exit Please enter your choice: 

הֶסבֵּר:

אנו מבצעים שתי משימות. הפונקציות צרכן() ו יַצרָן() לציין את המצב והתפעול של צרכן ו יַצרָן . ה שיטת producer(). תיצור את נעילת mutex ולקבוע האם המאגר הוא מלא כאשר הוא נקרא. כאשר המאגר מלא, לא ייווצר דבר. אם לא, זה יקרה לִיצוֹר , ולאחר מכן, לאחר ה הפקה , הוא ישכיב את עצמו לישון כדי לפתוח את נעילת mutex . כמו יַצרָן , הצרכן יוצר תחילה את נעילת mutex , בודק את בַּלָם , צורכת את מוצר , ולאחר מכן משחרר את המנעול לפני החזרה לישון.

א מונה (x) ישמש במהלך הייצור וימשיך לגדול עד שהיצרן ייצר את הפריט. עם זאת, הצרכן ייצור פחות מאותו מיוצר פריט (x) .

סיכום:

הרעיון של שימוש שתיים אוֹ שרשורים נוספים להפעיל תוכנית ידוע בשם ריבוי השחלות בשפת התכנות C. ריבוי השחלות מאפשר ביצוע בו זמנית של מספר משימות. רכיב ההפעלה הפשוט ביותר של תוכנית הוא a פְּתִיל . התהליך הוא הרעיון שניתן להשלים משימה על ידי פירוק שלה לכמה קטנות תהליכי משנה .

קובץ הכותרות pthread.h נדרש על מנת ליישם ריבוי פתילים ב-C מכיוון שלא ניתן לבצע זאת ישירות.