Operating System - Mutual Exclusion and Synchronization of Windows Threads

1. Experimental topic

Mutex and synchronization of Windows threads

2. The purpose of the experiment

(1) Review the relevant concepts of operating system processes and threads, and deepen the understanding of Windows threads.

(2) Understand mutex objects, use mutual exclusion and synchronization operations to write concurrent programs for producer-consumer problems, deepen the understanding of P (ie semWait), V (ie semSignal) primitives, and use P, V primitives to process Understanding of inter-synchronization and mutual exclusion operations

3. Experiment content (experimental principle/theoretical knowledge used, algorithm/program flow chart, steps and methods, key codes)

producer consumer problem

Step 1: Create a "Win32 Consol Application" project, then copy the program in Listing 5-1 and compile it into an executable

document.

Step 2: Run the executable file generated in Step 1 in the "Command Prompt" window, and list the running results.

Step 3: Read the source program carefully, find out the WINDOWS API function that creates the thread, and answer the following questions: the first thread

What is the first execution function (where does it start)? Which parameter is it in the API function that creates the thread?

Step 4: Modify the program in Listing 5-1, adjust the number of producer threads and consumer threads, so that the number of consumers is greater than

Producers, see the difference in results. Looking at the results of the run, what conclusions can you draw from them?

Step 5: Modify the program in Listing 5-1, and modify the initialization method of the semaphore EmptySemaphore according to the instructions in the program comments

method to see the difference in results.

Step 6: Based on the results of Step 4, and looking at MSDN, answer the following questions:

1) There are several parameters in CreateMutex, and what do they mean.

2) There are several parameters in CreateSemaphore, what does each represent, and the initial value of the semaphore is in which parameter.

3) What are the actual Windows API functions corresponding to the P and V primitives in the program, and write out these statements.

4) Can CreateMutex be replaced by CreateSemaphore? Try to modify program 5-1 to completely use the semaphore Mutex

CreateSemaphore and related functions are implemented. Write the statement to be modified.

question answer:

Step 3:

The Windows API function to create a thread is CreateThread.

The first execution function of the thread is the Producer function (the entry function of the producer thread). It is located in the third parameter lpStartAddress of CreateThread.

Step 4:

Adjust the number of producer threads and consumer threads so that the number of consumers is greater than that of producers, and the following results can be observed:

When the number of consumer threads is greater than the number of producer threads, consumer threads may wait more frequently for products in the buffer to consume, so consumer threads may execute slower.

Producer threads may produce products more frequently, because consumer threads consume products slower, there may be less empty space in the buffer, causing the number of times the producer thread waits for the EmptySemaphore to increase.

Step 5:

Modify the initialization method of the semaphore EmptySemaphore, set the second parameter to 0, that is, initialize to 0 vacancies, code example: EmptySemaphore = CreateSemaphore(NULL, 0, SIZE_OF_BUFFER, NULL).

As a result, all producer threads cannot produce products at the beginning, because the EmptySemaphore semaphore is initially 0, and the producer threads are blocked at WaitForSingleObject(EmptySemaphore, INFINITE), waiting for consumer threads to consume products.

Step 6:

There are 3 parameters in CreateMutex, the meaning of each representative is as follows:

Parameter 1: lpMutexAttributes, a pointer to the SECURITY_ATTRIBUTES structure, used to set the security attributes of the mutex object. It can be NULL, which means to use the default security attributes.

Parameter 2: bInitialOwner, indicating whether the calling thread has the initial ownership of the mutex object. TRUE means owned, FALSE means not owned.

Parameter 3: lpName, the name of the mutex object. Can be NULL.

There are 4 parameters in CreateSemaphore, and the meanings of each representative are as follows:

Parameter 1: lpSemaphoreAttributes, a pointer to the SECURITY_ATTRIBUTES structure, used to set the security attributes of the semaphore. It can be NULL, which means to use the default security attributes.

Parameter 2: lInitialCount, the initial counter value of the semaphore, that is, the number of available resources.

Parameter 3: lMaximumCount, the maximum counter value of the semaphore, that is, the upper limit of the counter.

Parameter 4: lpName, the name of the semaphore. Can be NULL. The initial value of the semaphore is in the second parameter lInitialCount.

The actual Windows API functions corresponding to the P and V primitives are:

The P operation corresponds to the WaitForSingleObject function, which is used to wait for the signal state of an object.

The V operation corresponds to the ReleaseSemaphore function, which is used to increase the counter value of the semaphore.

CreateMutex can be replaced by CreateSemaphore, but some modification is required:

Change CreateMutex to CreateSemaphore, and modify the initialization and use methods of the mutex.

Use WaitForSingleObject instead of WaitForSingleObject(mutex, INFINITE) to wait for the state of the semaphore.

Use ReleaseSemaphore instead of ReleaseMutex(mutex) to release the semaphore.

Modified code example:

// Initialize the mutex

mutex = CreateSemaphore(NULL, 1, 1, NULL);

// producer thread

WaitForSingleObject(emptySemaphore, INFINITE);

WaitForSingleObject(mutex, INFINITE);

// ...

ReleaseSemaphore(mutex, 1, NULL);

// consumer thread

WaitForSingleObject(fullSemaphore, INFINITE);

WaitForSingleObject(mutex, INFINITE);

// ...

ReleaseSemaphore(mutex, 1, NULL);

Note that since the initial value of the mutex counter initialized by CreateSemaphore is 1, 1 is used here as the initial counter value of CreateSemaphore, and the second parameter is set to 1 in WaitForSingleObject and ReleaseSemaphore.

4. Experimental results and analysis

 

Experimental results:

The program creates multiple producer threads and consumer threads.

The producer thread is responsible for producing the product, and puts the product into the buffer after each production.

The consumer thread is responsible for taking products from the buffer and consuming them.

Synchronization and mutual exclusion are realized between producers and consumers through mutual exclusion locks (Mutex) and semaphores (EmptySemaphore and FullSemaphore).

experiment analysis:

In the main function, a mutex (Mutex) and two semaphores (EmptySemaphore and FullSemaphore) are first created. Mutexes are used to protect access to shared resources, and semaphores are used to control the synchronization of producers and consumers.

According to the set number of producers and consumers, a corresponding number of threads are created, and the Producer and Consumer functions are executed respectively.

Before each production thread, the producer thread first waits for the EmptySemaphore semaphore to ensure that the buffer has an available position. Then acquire the mutex Mutex, perform the production operation, put the product into the buffer, and release the mutex Mutex and the FullSemaphore semaphore.

Before the consumer thread consumes the product each time, it first waits for the FullSemaphore semaphore to ensure that there is a product available in the buffer. Then acquire the mutex Mutex, perform a consumption operation, take out the product from the buffer, and release the mutex Mutex and the EmptySemaphore semaphore.

In each producer and consumer operation, relevant information is printed via the output statement, including the product number produced, the status of the buffer, and the product number consumed.

The while loop in the main function is used to control the running of the program. When the Enter key is pressed, p_ccontinue is set to false to end the thread running of the producer and the consumer.

Due to the multithreading and synchronization involved, actual results may vary due to the uncertainty of thread scheduling and race conditions. The above analysis is a possible situation.

It should be noted that this code has two types of comments when creating the semaphore, which can be modified as needed to observe the impact on program operation.

Overall, this experiment demonstrates the mechanism of synchronization and mutual exclusion between threads by simulating the behavior of producers and consumers. Producers and consumers interact through the buffer to ensure that the producer does not continue to produce when the buffer is full, and the consumer does not continue to consume when the buffer is empty. Through the reasonable use of mutexes and semaphores, the safety of threads and the correct execution sequence are guaranteed.

5. Summary and experience

1. Multi-thread programming: This experiment involves multi-thread programming, by creating multiple threads and using the thread synchronization mechanism to achieve coordination and communication between threads.

2. Producer-consumer model: This experiment is based on the producer-consumer model. The producer generates products and puts them in the buffer, and the consumer takes the products out of the buffer for consumption.

3. The use of the buffer: the buffer is designed as a circular queue, represented by an array. Producers and consumers access the buffer by maintaining read and write pointers (in and out) of the buffer.

4. Thread synchronization and mutual exclusion: In order to avoid the problem of data inconsistency caused by producers and consumers accessing the buffer at the same time, a mutual exclusion semaphore (Mutex) is used for mutual exclusion operations. At the same time, synchronization between producers and consumers is achieved through synchronous semaphores (FullSemaphore and EmptySemaphore).

5. Inter-thread communication: The producer and consumer communicate and synchronize through semaphores. When the buffer is full, the producer waits, and when the buffer is empty, the consumer waits.

6. Through the above experiments, you can deeply understand the concept and technology of multi-threaded programming, as well as the application of the producer-consumer model in a multi-threaded environment. This has important implications for concurrent programming and system design.

Guess you like

Origin blog.csdn.net/CSH__/article/details/131382726