// TestThread.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
#include <wtypes.h>
 
class SimonStore
{
public:
         SimonStore()
         {
                   m_ticket = 0;
                   m_bOpen = true;
                   // Every mutex has a thread id and reference count, it's associated to that thread
                   // A thread can refer to a mutex several times.
                   m_mutex = CreateMutex(NULL, false/*this thread doesn't own the mutex*/, _T("SimonStoreMutex"));
                   // WaitForSingleObject(m_mutex);
                   // ReleaseMutext(m_mutex);
         }
         ~SimonStore()
         {
                   if(m_mutex)
                   {
                            CloseHandle(m_mutex);
                   }
         }
 
         void SetOpen(bool bOpen)
         {
                   m_bOpen = bOpen;
         }
 
         bool IsOpen()
         {
                   return m_bOpen;
         }
 
         int GetTicketCount()
         {
                   return m_ticket;
         }
 
         static DWORD WINAPI Static_GetTicketCount(LPVOID lpParam)
         {
                   printf("Thread: GetCount started.\n");
                   SimonStore* pSS = (SimonStore*)lpParam;//This is a little tricy
                   if(pSS)
                   {
                            while(pSS->IsOpen())
                            {
                                     printf("Thread: GetCount, WaitForSingleObject m_mutex.\n");
                                     WaitForSingleObject(pSS->m_mutex, INFINITE);
                                     {
                                               Sleep(500);
                                               int num = pSS->GetTicketCount();                            
                                               printf("After GetCount: %d\n", num);
                                     }
                                     ReleaseMutex(pSS->m_mutex);
                            }
                   }
                   printf("Thread: GetCount ends.\n");
                   return 1;
         }
 
         void SetTicketCount(int count)
         {
                   m_ticket = count;
         }
 
         int Buy()    
         {
                   m_ticket = m_ticket + 1;      
                   return m_ticket;
         }
 
         static DWORD WINAPI Static_Buy(LPVOID lpParam)
         {
                   printf("Thread: Buy started.\n");
                   SimonStore* pSS = (SimonStore*)lpParam;
                   if(pSS)
                   {
                            while(pSS->IsOpen())
                            {
                                     printf("Thread: Buy, WaitForSingleObject m_mutex.\n");
                                     WaitForSingleObject(pSS->m_mutex, INFINITE);
                                     {
                                               Sleep(500);
                                               pSS->Buy();
                                               printf("After Buy: %d\n", pSS->GetTicketCount());
                                     }
                                     ReleaseMutex(pSS->m_mutex);
                            }
                   }
                   printf("Thread: Buy ends.\n");
 
                   return 1;
         }
 
         int Sell()
         {
                   m_ticket = m_ticket - 1;       
                   return m_ticket;
         }
 
         static DWORD WINAPI Static_Sell(LPVOID lpParam)
         {
                   printf("Thread: Sell started.\n");
                   SimonStore* pSS = (SimonStore*)lpParam;
                   if(pSS)
                   {
                            while(pSS->IsOpen())
                            {
                                     printf("Thread: Sell, WaitForSingleObject m_mutex.\n");
                                     WaitForSingleObject(pSS->m_mutex, INFINITE);
                                     {
                                              if(pSS->GetTicketCount() > 0)
                                               {
                                                        Sleep(500);
                                                        pSS->Sell();
                                                        printf("After Sell: %d\n", pSS->GetTicketCount());
                                               }
                                               else
                                               {
                                                        break;
                                               }
                                     }
                                     ReleaseMutex(pSS->m_mutex);
                            }
                   }
                   printf("Thread: Sell ends.\n");
 
                   return 1;
         }
 
         static DWORD WINAPI Static_WaitForCloseStore(LPVOID lpParam)
         {
                   printf("Thread: WaitForCloseStore stared.\n");
                   SimonStore* pSS = (SimonStore*)lpParam;
                   if(pSS)
                   {
                            for(int i=1;i<20;++i)
                            {
                                     Sleep(1000);//The store is open for 20 seconds
                            }
 
                            if(pSS->IsOpen())
                            {
                                     Sleep(500);
                                     printf("Thread: WaitForCloseStore close the store\n");
                                     pSS->SetOpen(false);
                            }
                   }
                   printf("Thread: WaitForCloseStore ends.\n");
                   return 1;
         }
 
private:
         int m_ticket;
         bool m_bOpen;
public:
         HANDLE m_mutex;
};
 
int _tmain(int argc, _TCHAR* argv[])
{
         HANDLE hThreadBuy, hThreadSell, hThreadCount, hThreadCloseStore;
         DWORD threadIdBuy, threadIdSell, threadIdCount, threadIdCloseStore;
 
         SimonStore simonStore;
         simonStore.SetTicketCount(100);//Initial ticket count is 100     
 
         hThreadBuy = CreateThread(NULL, 0, SimonStore::Static_Buy, &simonStore/*This is a little tricky*/, 0, &threadIdBuy);
         hThreadSell = CreateThread(NULL, 0, SimonStore::Static_Sell, &simonStore, 0, &threadIdSell);
         hThreadCount = CreateThread(NULL, 0, SimonStore::Static_GetTicketCount, &simonStore, 0, &threadIdCount);
         hThreadCloseStore = CreateThread(NULL, 0, SimonStore::Static_WaitForCloseStore, &simonStore, 0, &threadIdCloseStore);
 
         HANDLE handles[] ={hThreadBuy, hThreadSell, hThreadCount, hThreadCloseStore};
         WaitForMultipleObjects(4, handles, true, INFINITE);
 
         CloseHandle(hThreadBuy);
         CloseHandle(hThreadSell);
         CloseHandle(hThreadCount);
         CloseHandle(hThreadCloseStore);
 
         printf("All threads are ended.\n");
         int a;
         scanf("%d",&a);
 
         return 0;
}