Windows Programming _ sun Xin C ++ lesson16 thread synchronization and asynchronous socket programming

Source: Internet
Author: User
Tags htons

Windows Programming _ sun Xin C ++ lesson16 thread synchronization and asynchronous socket programming

Highlights of this section:
1. event object
2. Use the named event object to allow only one instance of the program to run
3. key code segment (critical section)
4. Thread deadlock
5. Message-based asynchronous socket programming-Chat Room Program 2
//************************************** *************************************
1. event object
(1) The event object also belongs to the kernel object, which contains a count, a Boolean value indicating whether the event is an automatic reset event or a manual reset event,
Another Boolean value used to indicate whether the event is in the notified or not notified status.
There are two different types of event objects: manual reset events and automatic reset events.
When a manually reset event is notified, all threads waiting for the event change to schedulable threads.
When an automatically reset event is notified, only one thread in the thread waiting for the event changes to a schedulable thread.
(2) create an event object
The createevent function creates an event object. Its function prototype is:
Handle createevent (
Lpsecurity_attributes lpeventattributes, // SD
Bool bmanualreset, // reset ype true indicates a manual reset event, and false indicates an automatic reset event object.
Bool binitialstate, // The initial state has an accident. True indicates a signal state, and vice versa.
Lptstr lpname // Object Name
);
Setevent is set to a signal state; resetevent is set to a non-signal state.
(3) manually reset the event object
//************************************** *************************************

# Include <windows. h> # include <iostream. h> DWORD winapi fun1 (lpvoid lpparameter // thread data); DWORD winapi fun2 (lpvoid lpparameter // thread data); int Index = 0; int tickets = 100; handle g_hevent; void main () {handle thread1, thread2; thread1 = createthread (null, 0, fun1, null, 0, 0); thread2 = createthread (null, 0, fun2, null, 0, 0 ); closehandle (thread1); closehandle (thread2); g_hevent = createevent (null, true, true, null); // The Creator resets the event object and initializes it to sleep (4000) in a signal state ); closehandle (g_hevent);} DWORD winapi fun1 (lpvoid lpparameter // thread data) {While (true) {waitforsingleobject (g_hevent, infinite); If (tickets> 0) {sleep (10); cout <"thread1 restart tickets:" <tickets -- <Endl; //} else break;} return 0 ;} DWORD winapi fun2 (lpvoid lpparameter // thread data) {While (true) {waitforsingleobject (g_hevent, infinite); If (tickets> 0) {sleep (10 ); cout <"thread2 extends tickets:" <tickets -- <Endl;} else break;} return 0 ;}

//************************************** **************************************
Running result:
...
Thread1 required tickets: 5
Thread2 required tickets: 4
Thread1 required tickets: 3
Thread2 required tickets: 2
Thread1 required tickets: 1
Thread2 required tickets: 0
//************************************** **************************************** ***
Verified, manually reset the event object, and all threads waiting for the event are started. Try the following solution:
//************************************** **************************************** **

# Include <windows. h> # include <iostream. h> DWORD winapi fun1 (lpvoid lpparameter // thread data); DWORD winapi fun2 (lpvoid lpparameter // thread data); int tickets = 100; handle g_hevent; void main () {handle thread1, thread2; thread1 = createthread (null, 0, fun1, null, 0, 0); thread2 = createthread (null, 0, fun2, null, 0, 0 ); closehandle (thread1); closehandle (thread2); g_hevent = createevent (null, true, true, null); sleep (4000); closehandle (g_hevent );} DWORD winapi fun1 (lpvoid lpparameter // thread data) {While (true) {waitforsingleobject (g_hevent, infinite); resetevent (g_hevent ); // manually reset if (tickets> 0) {sleep (10); cout <"thread1 required tickets:" <tickets -- <Endl; //} else break; setevent (g_hevent);} return 0;} DWORD winapi fun2 (lpvoid lpparameter // thread data) {While (true) {waitforsingleobject (g_hevent, infinite ); resetevent (g_hevent); If (tickets> 0) {sleep (10); cout <"thread2 restart tickets:" <tickets -- <Endl;} else break; setevent (g_hevent);} return 0 ;}

//************************************** **************************************** ***
Running result:
...
Thread1 required tickets: 5
Thread2 required tickets: 4
Thread1 required tickets: 3
Thread2 required tickets: 2
Thread1 required tickets: 1
Thread2 required tickets: 0
This indicates that the manually reset event object cannot solve the problem by using the above method.
//************************************** **************************************** ****
The event object is automatically reset. Only one thread waiting for the event object can be scheduled to run.
The experiment code is as follows:
//************************************** **************************************** ****

# Include <windows. h> # include <iostream. h> DWORD winapi fun1 (lpvoid lpparameter // thread data); DWORD winapi fun2 (lpvoid lpparameter // thread data); int tickets = 100; handle g_hevent; void main () {handle thread1, thread2; thread1 = createthread (null, 0, fun1, null, 0, 0); thread2 = createthread (null, 0, fun2, null, 0, 0 ); closehandle (thread1); closehandle (thread2); g_hevent = createevent (null, false, true, null); // automatically resets the event object
Sleep (4000); closehandle (g_hevent);} DWORD winapi fun1 (lpvoid lpparameter // thread data) {While (true) {waitforsingleobject (g_hevent, infinite ); // If (tickets> 0) {sleep (10); cout <"thread1 required tickets: "<tickets -- <Endl; //} else break; setevent (g_hevent ); // automatically reset an event. Only one thread can run the event. // The system sets the event object to be reset after the non-signal state is called.} return 0 ;} DWORD winapi fun2 (lpvoid lpparameter // thread data) {While (true) {waitforsingleobject (g_hevent, infinite); If (tickets> 0) {sleep (10 ); cout <"thread2 extends tickets:" <tickets -- <Endl;} else break; setevent (g_hevent);} return 0 ;}

//************************************** ***************************
Running result:
...
Thread2 required tickets: 6
Thread1 required tickets: 5
Thread2 required tickets: 4
Thread1 required tickets: 3
Thread2 required tickets: 2
Thread1 required tickets: 1
//************************************** ***************************
2. Use the named event object to allow only one instance of the program to run
//************************************** ***************************

# Include <windows. h> # include <iostream. h> handle g_hevent; // only one program instance is allowed to run void main () {g_hevent = createevent (null, false, false, "tickets "); // automatically reset the initial state of the event object without affecting the program function if (g_hevent) {If (error_already_exists = getlasterror () {cout <"only one instance can run! "<Endl; // restart another program will fail return ;}} cout <" running! "<Endl; sleep (4000); closehandle (g_hevent );}

 

//************************************** **************************
Shows the running effect:

 

//************************************** ***************************
3. key code segment (critical section)
A key code segment refers to a small code segment that
Before the code can be executed, it must be able to exclusively access certain resources. For details about the critical section, refer to Sun zhongxiu operating system tutorial.
(1) entercriticalsection function. Wait for the ownership of the object in the critical section. When the calling thread obtains the ownership, the function returns.
(2) The initializecriticalsection function starts a critical section object. Function prototype:
Void initializecriticalsection (
Lpcritical_section lpcriticalsection // critical section );
(3) The leavecriticalsection function releases critical zone resources. Its prototype is:
Void leavecriticalsection (
Maid section // critical section
);
(4) deletecriticalsection releases all resources of an unoccupied critical area object.
//************************************** ***********************************

# Include <windows. h> # include <iostream. h> # include <WINBASE. h> DWORD winapi fun1 (lpvoid lpparameter // thread data); DWORD winapi fun2 (lpvoid lpparameter // thread data); void showlasterror (); int tickets = 100; critical_section g_cs; void main () {handle thread1, thread2; thread1 = createthread (null, 0, fun1, null, 0, 0); thread2 = createthread (null, 0, fun2, null, 0, 0 ); closehandle (thread1); closehandle (thread2); initializecriticalsection (& g_cs); // initialize the object sleep (3000); deletecriticalsection (& g_cs ); // release the object resource in the critical section} DWORD winapi fun1 (lpvoid lpparameter // thread data) {While (true) {entercriticalsection (& g_cs); If (tickets> 0) {sleep (10); cout <"thread1 required tickets:" <tickets -- <Endl; // critical zone mutual exclusion problem} else break; leavecriticalsection (& g_cs );} return 0;} DWORD winapi fun2 (lpvoid lpparameter // thread data) {While (true) {entercriticalsection (& g_cs); // enter the critical section if (tickets> 0) {sleep (10); cout <"thread2 restart tickets:" <tickets -- <Endl;} else break; leavecriticalsection (& g_cs);} return 0 ;}

//************************************** **********************************
Running result:
...
Thread2 required tickets: 6
Thread1 required tickets: 5
Thread2 required tickets: 4
Thread1 required tickets: 3
Thread2 required tickets: 2
Thread1 required tickets: 1
4. Thread deadlock
The philosophers wait for each other's resources while waiting for each other. In the following program, when thread 1 gets access to critical Zone A, it goes to sleep,
Then thread 2 runs to obtain the access permission for Critical Zone B, but thread 2 also goes to sleep. The operating system switches to thread 1 for execution, but thread 1 cannot obtain the access permission for Critical Zone B,
Therefore, the operating system switches to thread 2 for execution, but thread 2 cannot obtain the access permission of Critical Zone A. Therefore, the two threads wait for each other's access permission in the critical zone to both wait for a deadlock.
The Demo code of the deadlock process is as follows:
//************************************** **************************************** ****
# Include <windows. h>
# Include <iostream. h>
# Include <WINBASE. h>
DWORD winapi fun1 (
Lpvoid lpparameter // thread data
);
DWORD winapi fun2 (
Lpvoid lpparameter // thread data
);
Int tickets = 100;
Critical_section g_csa;
Critical_section g_csb;
// DEMO code of thread deadlock
// When thread 1 gets access to critical Zone A, it goes to sleep. Then thread 2 gets access to critical zone B.
// But thread 2 also goes to sleep. The operating system switches to thread 1 for execution, but thread 1 cannot obtain the access permission of Critical Zone B.
// The operating system switches to thread 2 for execution, but thread 2 cannot obtain the access permission of critical section.
// Therefore, the two threads wait for each other's access permission in the critical section of the other side.
Void main ()
{
Handle thread1, thread2;
Thread1 = createthread (null, 0, fun1, null, 0, 0 );
Thread2 = createthread (null, 0, fun2, null, 0, 0 );
Closehandle (thread1 );
Closehandle (thread2 );
Initializecriticalsection (& g_csa); // initialize the critical area object
Initializecriticalsection (& g_csb );
Sleep (4000 );
Deletecriticalsection (& g_csa); // release the resource sequence of objects in the critical section.
Deletecriticalsection (& g_csb );
}
DWORD winapi fun1 (
Lpvoid lpparameter // thread data
)
{
While (true)
{
Entercriticalsection (& g_csa );
Sleep (100 );
Entercriticalsection (& g_csb );
// Mutex code segment
If (tickets> 0)
{
Sleep (10 );
Cout <"thread1 effectickets:" <tickets -- <Endl;
}
Else
Break;
// Mutex code segment
Leavecriticalsection (& g_csa );
Leavecriticalsection (& g_csb );
}
Return 0;
}
DWORD winapi fun2 (
Lpvoid lpparameter // thread data
)
{
While (true)
{
Entercriticalsection (& g_csb); // enter the critical section
Sleep (100 );
Entercriticalsection (& g_csa );
If (tickets> 0)
{
Sleep (10 );
Cout <"thread2 extends tickets:" <tickets -- <Endl;
}
Else
Break;
Leavecriticalsection (& g_csa );
Leavecriticalsection (& g_csb );
}
Return 0;
}

//************************************** **************************************** *****
Thread 1 and thread 2 do not get execution opportunities during program execution. Therefore, the program running result is time-consuming.
//************************************** **************************************** *****
Summary of mutex semaphores:
The use of mutex objects and event objects belongs to the kernel object, and the use of kernel objects for thread synchronization is slow, but the use of mutex objects and event objects such as kernel objects,
It can be synchronized between various threads in multiple processes. Key code segments work in the user mode, and the synchronization speed is fast. However, when key code segments are used, they are easy to enter the deadlock status,
The timeout value cannot be set when the key code segment is entered.
5. Message-based asynchronous socket programming-Chat Room Program 2
(1) Windows Socket performs I/O operations in two modes, blocking and non-blocking. In blocking mode, before the I/O operation is complete, the winsocket function that executes the operation will remain waiting and the program will not be returned immediately. In non-blocking mode,

The Winsock function returns immediately in any case. To support the Windows message driver, Windows Sockets enables application developers to conveniently process network communication. It uses message-based Asynchronous access policies for network events. Asynchronous overlay

Word mode can improve the program running efficiency.
(2) the asynchronous selection function wsaasyncselect () of Windows Sockets provides the network event selection for the message mechanism. When a network event of its level is used, the window function corresponding to the Windows application receives a message indicating that

Network events and event-related information.
(3) Notifications of network events requested by the wsaasyncselect function based on the Windows message mechanism. This function will automatically change the socket to non-blocking mode.
(4) The wsaenumprotocols function returns network protocol information.
(5) The resource release code in program socket initialization and destructor is as follows:
//************************************** **************************************** *****
// Initially load the socket Library File
// # Include <winsock2.h> the header file contains # include "stdafx. H"
// Add ws2_32.lib library file reference at the same time
Bool cchat2app: initinstance ()
{
Word wversionrequested;
Wsadata;
Int err;
 
Wversionrequested = makeword (2, 2); // version negotiation Version 2.2
 
Err = wsastartup (wversionrequested, & wsadata );
If (Err! = 0 ){

Return false;
}
If (lobyte (wsadata. wversion )! = 2 |
Hibyte (wsadata. wversion )! = 2)
{
Wsacleanup ();
Return false; // if a failure occurs, false is returned.
}
...
}
Cchat2app ::~ Cchat2app ()
{
Wsacleanup (); // terminate library file reference
}
Cchat2dlg ::~ Cchat2dlg ()
{
If (m_socket)
Closesocket (m_socket); // closes the socket
}
Bool cchat2dlg: oninitdialog ()
{
...
Initsocket (); // socket Initialization
Return true; // return true unless you set the focus to a control
}
//************************************** **************************************** *****
(6) implementation code of the message sending and receiving dialog box class in the program:
//************************************** **************************************** *****

// Send data void cchat2dlg: onbtnsend () {// todo: add your control notification handler code here DWORD dwip; sockaddr_in addrto; cstring sendstr; int Len; wsabuf; cstring strhostname; hostent * phostent; If (getdlgitemtext (idc_edit_hostname, strhostname), strhostname = "") {(optional *) getdlgitem (idc_ipaddress)-> getaddress (dwip ); addrto. sin_addr.s_un.s_addr = htonl (dwip);} else {phostent = Ge Thostbyname (strhostname); // obtain host information through the host name if (phostent! = NULL) addrto. sin_addr.s_un.s_addr = * (DWORD *) phostent-> h_addr_list [0]); // the pointer conversion Memory Model concept else {MessageBox ("the computer name is incorrect! "); Setdlgitemtext (idc_edit_hostname," "); setdlgitemtext (idc_edit_send," "); Return ;}} addrto. sin_family = af_inet; addrto. sin_port = htons (6000); getdlgitemtext (idc_edit_send, sendstr); Len = sendstr. getlength (); wsabuf. buf = sendstr. getbuffer (LEN); wsabuf. len = Len + 1; DWORD dwsend; If (socket_error = wsasendto (m_socket, & wsabuf, 1, & dwsend, 0, (sockaddr *) & addrto, sizeof (sockaddr ), null, null) {MessageBox ("Send Data failed! "); Return;} setdlgitemtext (idc_edit_send," ") ;}// accept data void cchat2dlg: onrecvdata (wparam, lparam) {// todo: add your control notification handler code here // process network read events // The low word of lparam specifies the network event that has occurred switch (loword (lparam) {Case fd_read: wsabuf; wsabuf. buf = new char [200]; wsabuf. len = 200; DWORD dwread; DWORD dwflag = 0; sockaddr_in addrfrom; Cstring recvstr; cstring tempstr; int Len = sizeof (sockaddr); hostent * phost; // In the wsarecvfrom function, at the same time, the advantage of using different buffers to accept data is that you do not need to call the function to split the byte stream to obtain information if (socket_error = wsarecvfrom (m_socket, & wsabuf, 1, & dwread, & dwflag, (sockaddr *) & addrfrom, & Len, null, null) {MessageBox ("failed to create socket! "); Return;} phost = gethostbyaddr (char *) (& addrfrom. sin_addr.s_un.s_addr), sizeof (sockaddr), af_inet); // obtain user host information through IP address if (phost = NULL) recvstr. format ("Message from % s: % s", inet_ntoa (addrfrom. sin_addr), wsabuf. buf); else recvstr. format ("Message from % s: % s", phost-> h_name, wsabuf. buf); recvstr + = "\ r \ n"; getdlgitemtext (idc_edit_recv, tempstr); recvstr + = tempstr; setdlgitemtext (idc_edit_recv, recvstr); break;} // Initialize the socket bool cchat2dlg: initsocket () {m_socket = wsasocket (af_inet, sock_dgram, 0, null, 0, 0); If (invalid_socket = m_socket) {MessageBox ("failed to create socket! "); Return false;} sockaddr_in addrsocket; addrsocket. sin_addr. s_un. s_addr = htonl (inaddr_any); addrsocket. sin_family = af_inet; addrsocket. sin_port = htons (6000); int retval; retval = BIND (m_socket, (sockaddr *) & addrsocket, sizeof (sockaddr); If (retval = socket_error) {MessageBox ("failed to create socket! "); Return false;} // register the network event fd_read to process the message um_sock if (socket_error = wsaasyncselect (m_socket, m_hwnd, um_sock, fd_read )) {MessageBox ("failed to register the network read event! "); Return false;} return true ;}

//************************************** **************************************** *****
Shows the program running effect:

//************************************** **************************************** *****
Summary:
1. This section describes the thread synchronization methods, including two Processing Methods Based on Time objects and critical section. Pay attention to their respective features.
2. Understand the principles of deadlocks and avoid deadlocks in future programming.
3. Introduced asynchronous socket programming based on message mechanism, and implemented chat room programs. Pay attention to the advantages of asynchronous sockets compared with the multi-thread chat room program.

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.