Waitcommevent or writefile causes deadlock when writing a serial Program

Source: Internet
Author: User

{
Newhighlight (Event)
} ">

Comparison Between running mechanism of WINXP and wince serial port
// ================================================ ========================================
// Title:
// Comparison of Running Mechanism between WINXP and wince serial port
// Author:
// Norains
// Date:
// Saturday 11-November-2006
// Passed environment:
// PC: WINXP + vc6.0
// Ce: wince4.2 + evc4.0
// ================================================ ========================================
You can see that in the desktop operating system, there are two serial communication modes: synchronous and asynchronous. there is only one type of wince, but the document does not indicate the mode of ownership. in fact, the serial port communication mode of Wince is more like synchronous and asynchronous.
This section briefly introduces synchronization and Asynchronization. the so-called synchronization means that the read or write operations on the same device or file (only the serial port COM1 in the text) must wait until the previous operation is completed. for example, if you call the readfile () function to read the serial port, but the previous writefile () operation is incomplete, the readfile () operation is blocked until the writefile () operation is complete. asynchronous means that the currently called Operation is executed no matter whether the previous operation is complete or not. in asynchronous mode, even if the writefile () is not completed, readfile () will be executed immediately.


1. Differences in createfile () Parameters
First, describe the parameter differences between the port opened by wince and WINXP. take the serial port COM1 as an example. The name of Wince is "COM1:", and WINXP is "COM1". The only difference between the two is that there are multiple semicolons under wince.
For example:
Handle Hd = createfile (text ("COM1:"), generic_read | generic_write, 0, null, open_existing, 0, null); // WinCE
Handle Hd = createfile (text ("COM1"), generic_read | generic_write, 0, null, open_existing, 0, null); // WINXP
In this case, in the default environment, the text Macro will be compiled into dubyte in wince, while WINXP is a single byte. in other words, text ("COM1") is equivalent to L "COM1" under wince, while WINXP is "COM1 ".


2. Single-thread comparison
Use Code as an example to illustrate the image comparison. this is a single-threaded code. First, write the serial port and then read it. for WINXP, This is the synchronization mode. (The Code irrelevant to the topic is omitted)
Int winapi winmain (hinstance,
Hinstance hprevinstance,
Lptstr lpcmdline,
Int ncmdshow)
{
...
Handle hcom = createfile (text ("COM1:"), generic_read | generic_write, 0, null, open_existing, 0, null); // WinCE
// Handle COM = createfile (text ("COM1"), generic_read | generic_write, 0, null, open_existing, 0, null); // WINXP

...
DWORD dwbytes;
If (writefile (hcom, text ("COM1:"), 5, & dwbytes, null) = false) // WinCE
// If (writefile (hcom, text ("COM1"), 5, & dwbytes, null) = false) // WINXP
{
Return 0x05;
}

...
DWORD dwread;
Char szbuf [max_read_buffer];
If (readfile (hcom, szbuf, max_read_buffer, & dwread, null) = false)
{
Return 0x10;
}

...
}
After experiment, we can find that this code works normally in both Windows XP and Windows XP, and its performance is the same. It is only executed after the writefile () function returns ().
Because the asynchronous mode works normally in a single thread, the only difference is that when writefile () is executed, it may also execute readfile () (depending on the time when the writefile () function is executed ), the table is not listed here.

3. multi-thread comparison
The performance of a single thread is the same. What about multithreading? The following code uses multithreading. It first creates a read thread to monitor whether new data arrives at the serial port, and then writes data to the serial port in the main thread.
Assume that there are two devices, device A and Device B, and the following code runs on device A. Device B only responds. in other words, B returns a response signal only when a sends data to B.
// Main thread
Int winapi winmain (hinstance,
Hinstance hprevinstance,
Lptstr lpcmdline,
Int ncmdshow)
{
...
Createthread (null, 0, readthread, 0, 0, & dwthrdid); // create a read thread.

...
Handle hcom = createfile (text ("COM1:"), generic_read | generic_write, 0, null, open_existing, 0, null); // WinCE
// Handle COM = createfile (text ("COM1"), generic_read | generic_write, 0, null, open_existing, 0, null); // WINXP

...
DWORD dwbytes;
If (writefile (hcom, "At/R/N", 4, & dwbytes, null) = false) // WinCE
// If (writefile (hcom, "At/R/N", 5, & dwbytes, null) = false) // WINXP
{
Return 0x05;
}

...

}

// Read thread
DWORD winapi readthread ()
{
...
Setcommmask (hcom), ev_rxchar );
DWORD dwcommstatus = 0;
If (waitcommevent (hcom), & dwcommstatus, null) = false)
{
// Clear the error flag
DWORD dwerrors;
COMSTAT;
Memset (& COMSTAT, 0, sizeof (COMSTAT ));
Clearcommerror (hcom, & dwerrors, & COMSTAT );
Return 0x15;
}

...
Char szbuf [max_read_buffer] = {0 };
DWORD dwread;
If (readfile (hcom), szbuf, max_read_buffer, & dwread, null) = false | dwread = 0)
{
Return 0x20;
}

...
}

This code runs completely normally under wince. While the reading thread monitors the received data, the main thread smoothly sends data out.
However, the same Code cannot be completed in WINXP. run this code and we will find that the CPU usage is as high as 99%. through one-step debugging, it is found that the two threads are stuck in the waitcommevent () and writefile () functions respectively. according to the definition of synchronization mode, the current operation on the device must wait until the previous operation is completed. in the above Code, because Device B does not receive a command from device A and does not send a response to device A, the waitcommevent () function keeps occupying the serial port because it does not detect receiving data; waitcommevent () keeps occupying the serial port so that writefile () is blocked because it does not get the serial port resources, which causes a deadlock.
This situation does not occur on WinCE. As long as waitcommevent () and writefile () are not in the same thread, they can work normally. This should be related to the System Scheduling Method.

If you want to perform both waitcommevent () and writefile () operations on the PC, you need to rewrite the serial port mode to the asynchronous mode.
The changed code is as follows:

// Main thread
Int winapi winmain (hinstance,
Hinstance hprevinstance,
Lptstr lpcmdline,
Int ncmdshow)
{
...
Createthread (null, 0, readthread, 0, 0, & dwthrdid); // create a read thread.

...
Handle COM = createfile (text ("COM1"), generic_read | generic_write, 0, null, open_existing, 0, file_flag_overlapped );

...
Overlapped olwrite;
Memset (& olwrite, 0, sizeof (m_olwrite ));
Olwrite. hevent = createevent (null, true, false, null );
 
DWORD dwbytes;
If (writefile (hcom, "At/R/N", 4, & dwbytes, & olwrite) = false)
{
If (getlasterror ()! = Error_io_pending)
{
Return 0x20;
}
}
If (getoverlappedresult (hcom, & olwrite, & dwbytes, true) = false)
{
Return 0x25;
}
...

}

// Read thread
DWORD winapi readthread ()
{
...
Memset (& olwaite, 0, sizeof (olwaite ));
Olwaite. hevent = createevent (null, true, false, null );
Setcommmask (hcom), ev_rxchar );
DWORD dwcommstatus = 0;
Waitcommevent (hcom, & dwcommstatus, olwaite );
DWORD dwbyte; // norains: It is only suitable for the getoverlappedresult (), not undefined here.
If (getoverlappedresult (hcom, olwaite, & dwbyte, true) = false)
{
If (getlasterror ()! = Error_io_pending)
{
Return 0x30;
}
// Clear the error flag
DWORD dwerrors;
COMSTAT;
Memset (& COMSTAT, 0, sizeof (COMSTAT ));
Clearcommerror (hcom, & dwerrors, & COMSTAT );
Return 0x35;
}

...
Memset (& olread, 0, sizeof (olread ));
Olread. hevent = createevent (null, true, false, null );
Char szbuf [max_read_buffer] = {0 };
DWORD dwread;
If (readfile (hcom, szbuf, max_read_buffer, & dwread, olread) = false)
{
If (getlasterror ()! = Error_io_pending)
{
Return 0x40;
}
If (getoverlappedresult (hcom, olread, & dwread, true) = false)
{
Return 0x45;
}
If (dwread = 0)
{
Return 0x50;
}
}

...
}

After testing the changed code, we can find that waitcommevent () and writefile () can be called simultaneously under WINXP without causing a deadlock.
Here we can find the differences between the serial scheduling of wince and WINXP: in a single thread, the serial running mode of Wince is consistent with the synchronous working mode of the WINXP serial port; in multithreading, the serial port running mode of Wince is consistent with the asynchronous mode of WINXP. although it is impossible to compare whether the single serial port mode of Wince is more advantageous than that of WINXP, it can be confirmed that the serial port call method of Wince has brought great convenience to programmers.


4. WINXP asynchronous mode: two methods to determine whether the operation is successful
In the asynchronous mode of WINXP, writefile (), readfile (), and waitcommevent () are returned if the operation is not completed, therefore, you cannot simply judge whether the returned value is true or false.
Use the readfile () function as an example.
One is the method used above:
If (readfile (hcom, szbuf, max_read_buffer, & dwread, olread) = false)
{
If (getlasterror ()! = Error_io_pending)
{
Return 0x40;
}
If (getoverlappedresult (hcom, olread, & dwread, true) = false)
{
Return 0x45;
}
If (dwread = 0)
{
Return 0x50;
}
}
If readfile () returns true, it indicates that the read file has been completed. however, this situation will hardly occur, because the read and write operations on peripherals are very slow compared to the memory read and write operations, so the readfile () function has not been executed, and the program has been executed to the next statement.
When readfile () returns false, use the getlasterror () function to determine whether the read operation is performed in the background. if it is performed in the background, call the getoverlappedresult () function to obtain the result of the readfile () function. note that the last parameter of the getoverlappedresult () function must be set to true, indicating that the result is returned only after the readfile () function is completed in the background. if the last parameter is set to false, the getoverlappedresult () function will return immediately even if readfile () is still executed in the background, resulting in an incorrect judgment.

The other is to call the waitforsingleobject function for this purpose:
If (readfile (hcom, szbuf, max_read_buffer, & dwread, olread) = false)
{
If (getlasterror ()! = Error_io_pending)
{
Return 0x40;
}
If (waitforsingleobject (olread. hevent, infinite )! = Wait_object_0)
{
Return 0x55;
}
If (getoverlappedresult (hcom, olread, & dwread, false) = false)
{
Return 0x45;
}
If (dwread = 0)
{
Return 0x50;
}
}
Because after readfile () is executed in the background, an event will be sent, so here you can call waitforsingleobject () to wait until the readfile () is executed, and then call getoverlappedresult () to get readfile (). note that the last parameter of getoverlappedresult () must be set to false because waitforsingleobject () has captured the event sent by readfile, no more events are passed to the getoverlappedresult () function. if the last getoverlappedresult () parameter is set to true at this time, the thread will stay in the getoverlappedresult () function without executing it. -------------------------------------------------------------------------------- the serial programming idea in EVC is roughly the same as that in VC, but pay attention to the following points:
1) Windows CE is unicode encoded. When reading characters, pay attention to the determination of the number of bytes.
2) EVC does not support overlapping I/O. All parameters related to the overlapped structure in all functions must be set to null.
3) EVC does not support buildcommdcb () and getoverlappedresult ().
4) the serial port Writing Method in EVC is different from that in general VC. For example, Serial Port 1 must be written as "COM1:" rather than "COM1 ".

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.