Realization of Multithreading in VC 6.0: Taking Railway Ticket Sale as an Example

Keywords: Windows Linux Programming

Recently, in the process of learning C++ I learned about multithreading, and found that "mutex lock" is very useful. I want to realize it, but I am not familiar with linux system, so I can only try to implement it on windows with the help of VC++6.0. In the process of data type conversion and other issues have been doing stumbling, and ultimately only come up with a framework, there are still many details to be improved. Summarize it first and continue to explore later.

Problem statement

  • This paper mainly discusses the sale of train tickets. There will be different windows selling tickets at the same time. If the operation of each window is not managed, the background ticket data will be wrong. In order to solve this problem, mutex can be introduced. The specific operations are as follows: if a window wants to modify background data, it needs to first obtain operation privileges (i.e. mutex); after the mutex is locked by a window, the window can modify data; after the operation of the window on data is completed, the mutex is released. . At this point, other window threads requesting mutexes can perform similar operations. Note that the request mutex operation here uses the function WaitForSingleObject (), which waits for a mutex. If the mutex cannot be obtained immediately, it will enter a dormant waiting state, consuming only a small amount of CPU time. WaitForSingleObject () supports queues, where multiple threads request mutexes at the same time, and threads that initiate requests first receive mutexes first.
  • From the above analysis, we can see that the introduction of "mutex" can ensure that only one thread at a certain time in the operation of data, thus preventing data errors.
  • The program is mainly divided into three parts: main function, header file (declaring structure and thread entry function needed) and implementation of thread entry function.

Programming

  1. ticketsSale.h - Header file
#include <windows.h>
#include <string>
#include <iostream>

using namespace std;
#define NameLength 20		//Ticket name up to 20 characters

//Define the number and name of tickets stored in the system by the structure
typedef struct _Tickets
{
	int tCount;
	char TicketsName[NameLength];

	//Default initialization of structured objects
	_Tickets():tCount(0)	//Number initialized by default is 0
	{
		memset(TicketsName,0,NameLength*(sizeof(char)))	;
	}

}TICKETS;		//Structural alias TICKETS

//Parametric Structures Defining Thread Entry Functions
typedef struct _Thread
{
	TICKETS *ptickets;		//Ticket Information in Current System
	char threadName[NameLength];		//Thread name

    _Thread():ptickets(NULL)	//Ticket information (structure object) is initialized to empty NULL
    {
        memset(threadName, 0, NameLength * sizeof(char));
    }
}THREADS;		//Structural alias THREADS

//Thread entry function
DWORD WINAPI SaleTicket(LPVOID lpParameter);		//Note the specification for defining threaded functions
  1. SaleTicket.cpp - Thread Entry Function
#include <windows.h>
#include <string>
#include <iostream>
#include "ticketsSale.h"

using namespace std;

extern HANDLE g_hMutex;		//External mutex

//Thread entry function
DWORD WINAPI SaleTicket(LPVOID lpParameter)		//Note the specification for defining threaded functions
{

	// Mandatory type conversion of incoming parameters from untyped pointer to integer pointer
	THREADS * pthread = (THREADS *)lpParameter;  

	//Ticket information to be processed, obtained by pointer
	//The purpose of getting ticket information by pointer is to ensure that the processing of tickets can be synchronized among multi-threads.
	TICKETS * psaletickets = pthread->ptickets; 

	while(psaletickets->tCount>0)
	{
		//Request to obtain a mutex lock with waiting time infinite
        WaitForSingleObject(g_hMutex, INFINITE);

		//After obtaining the mutex, the number of tickets may have changed and need to be re-inquired and judged.
		if((psaletickets->tCount)>0)
		{
			cout << pthread->threadName << "Sell out"<< psaletickets->TicketsName<< "Tickets;";
			cout << "Ticket number:" << psaletickets->tCount<<endl;
			psaletickets->tCount--;		//Modify Background Remaining Ticket Information
			cout << "Remaining tickets "<<psaletickets->tCount << "Zhang "<<endl;
			cout <<endl;
		}
		else		//There are no tickets left.
		{
			cout << "Ticket failure, there is no spare ticket! "<<endl;
		}
	    Sleep(100);
	    
        //Operation completed, release mutex lock
        ReleaseMutex(g_hMutex);
	}
	
	return 0;

}
  1. main.cpp - Main Program Entry
#include <windows.h>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <sstream>
#include "ticketsSale.h"

using namespace std;

HANDLE g_hMutex;	//This is a global variable, declared outside the main function to be referenced elsewhere.

int main()
{
	//Create a mutex for inter-thread synchronization
	g_hMutex = CreateMutex(NULL, FALSE, NULL);

	//Initialize train ticket information
    TICKETS ticket;
    ticket.tCount = 100;
    strcpy(ticket.TicketsName, "Beijing-->Ganzhou");

	const int ThreadsNum = 5;		//There are five threads that can manipulate data

	//In array declarations, subscripts must be constants, so ThreadsNum is declared const
	THREADS threadSale[ThreadsNum];		//Thread Structures Array 
    HANDLE hThread[ThreadsNum];		//Used to save the return handle after the thread was created

	//Create five threads in turn
	for(int i =0;i<ThreadsNum;i++)
	{
		//The parameter structure that needs to be passed in to construct the thread entry function
		(threadSale[i]).ptickets = &ticket;	

		//Using stringstream Stream to Realize Digital String Conversion
		stringstream s;
		s << i;
		string name = "window"+s.str();

		strcpy(threadSale[i].threadName,name.c_str());

		//Create threads
        hThread[i] = CreateThread(NULL, NULL, SaleTicket, &threadSale[i], 0, NULL);
	}

	for(int j = 0;j<ThreadsNum;j++)
	{	        
		//Close threads
        CloseHandle(hThread[j]);
	}

	system("pause");
	return 0;
}
  1. Operation results
Window 0 sells tickets for Beijing - > Ganzhou; Ticket number: 100
 99 remaining tickets

Please press any key to continue... Window 1 sells tickets for Beijing - > Ganzhou; Ticket number: 99
 98 remaining tickets

Window 2 sells tickets for Beijing - > Ganzhou; Ticket number: 98
 97 remaining tickets

Window 3 sells tickets for Beijing - > Ganzhou; Ticket number: 97
 96 remaining tickets

Window 4 sells tickets for Beijing - > Ganzhou; Ticket number: 96
 95 remaining tickets

Window 0 sells tickets for Beijing - > Ganzhou; Ticket number: 95
 94 remaining tickets
  1. The function of multi-thread synchronization is basically realized, but the main thread and the sub-threads are executed together, which is different from the desired results. Ideally, the main thread should be independent of the sub-thread. How to do this? Keep it for further exploration.

Posted by system_critical on Thu, 15 Aug 2019 02:54:43 -0700