Last timeArticleWe have discussed how to design an ASP. NET web service to process persistent connection requests. Many people have asked this question. How can I hold the request and keep it open for 30 seconds? This is actually very simple. Just sleep:
Thread. Sleep (30*1000 );
However, the problem is that we don't have to wait 30 seconds to check whether an event needs to be returned, but that an event can be returned at any time within these 30 seconds. Therefore, we need a mechanism to check whether an event has occurred while waiting.
Monitor Model
In. net, the most familiar Thread Synchronization Model should be the monitor model. Have you heard of it? It is the lock keyword of C #. In fact, it is compiled into a pair of monitor. Enter () and monitor. Exit ().
Using the lock command, we can create a critical section for an object,CodeThe lock of the object must be obtained before execution at the entry of the critical section, and the lock can be released at the exit of the critical section. However, this model is not suitable for solving our problem, because we need to wait for an event. If we use lock to wait, we need to lock the object outside the Web service first, then, when the event is triggered, the Web Service is unlocked and enters the critical area smoothly.
In fact, there is a better choice for this type of blocking, that is, mutex.
Mutex Model
Mutex is the abbreviation of mutual exclusive. How does mutex work? This is a bit like a bank queuing call system. All the waiting persons are waiting in the lobby to wait (wait). When a service window is idle, it will send a signal (signal) to notify the next person waiting for the service. In short, all threads that execute wait commands are waiting, and each signal can end a thread and wait for execution to continue.
In. net, the wait and signal operations correspond to the mutex. waitone () and mutex. releasemutex () methods respectively. We can let the Web service thread use mutex. waitone () to enter the waiting state, and use mutex. releasemutex () to notify the Web service thread when an event occurs. Because it must be in mutex. after releasemutex () occurs, mutex. waitone () can continue to execute, so if it can be executed, it proves that there must be an event and mutex is called. releasemutext (). At this time, you can read the event message with confidence.
Simple Example
After selecting to use the mutex model, we will compile a simple example. First, we need to define a mutex In the WebService derived class and a message string.
Mutex = new mutex ();
String message;
Then, we define two webmethods. In order to simplify the problem, we chose the two function signatures mentioned in the previous article, that is, we can only send and receive functions in one web service, without the concept of sending targets, there is no timeout concept and no reliability design. At the same time, we replace the message type with a normal string for testing.
First, write the function for sending messages:
Public void send (string message ){
This. Message = message;
This. mutex. releasemutex ();
}
In this sending function, we first put the message into the global variable in the class, and then let the global mutex class release a signal. At this time, if a thread is waiting, it can be executed immediately. If no thread is waiting at this time, the next wait thread will be able to continue to execute to the blocked place without being blocked.
Now let's compile the function for receiving messages:
Public String wait (){
This. mutex. waitone ();
Return this. message;
}
The receiving function enters the Wait Status at the beginning. After signal is obtained, the global message is returned to the client.
Experience
Finally, we can test our code through the web test interface supported by ASP. NET web service itself. We open two browser windows, one for sending () and the other for wait. Then we can test it as follows:
- Run send ("hello") and wait (). Now you can see "hello ".
-
- First, run wait () to wait for the response. Then, run send ("hello "). Then you can see that the wait () section returns "hello.
-
- Run the command in the following order: Send ("hello"); wait (); send ("world"); wait ();
-
- Run the following command: Send ("hello"); send ("world"); wait ();
-
- Run the command in the following order: Wait (); wait (); send ("hello"); send ("world ");
- Run the command in the following order: Wait (); send ("hello"); wait (); send ("world ");
You will find some strange results: "world" and "world" are returned for the 3rd tests ". The wait () thread that first executes does not necessarily return "hello" for the 5th tests. In some cases, the latter is not a problem. In particular, in persistent connections, the second wait () thread is waiting, so we can ignore it. The former is because there is no message queue. We only have one message window, so we can only cache the last message. We will solve this problem in the next article.
Summary
In this article, we see the differences between different thread synchronization models. The lock of the Monitor Model is essentially a semaphore, that is, a mutex that cannot be consecutive signal. After a signal is sent, it must be received by a wait before the next signal can be performed. At the same time, semaphore also limits that signal and wait must be executed in pairs in the same thread, while mutex does not. Although. NET is optimized for the monitor model, we only need to use the mutex model to solve our needs.
Then, we wrote a small function for sending and receiving consumers, implementing the blocking web service we wanted. At the same time, we also saw the problem caused by no message queue, so we are sure to create a message queue.