int main() {
    try{
        CQueue<int> cq;
        for(int i = 0; i < 10; i++) 
            cq.appendTail(i);
        for(int i = 0; i < 10; i++) 
            cout << cq.deleteHead() << ' ';
        cout << endl;
        cq.deleteHead();
    } catch(exception &e) {
        cerr << e.what() << endl;
    }


    try{
        CStack<int> cs;
        for(int i = 0; i < 10; i++) 
            cs.push(i);
        for(int i = 0; i < 10; i++) 
            cout << cs.pop() << ' ';
        cout << endl;
        cs.pop();
    } catch(exception &e) {
        cerr << e.what() << endl;
    }
    return 0;
}
int main(int argc, char *argv[])
{
    CQueue<int> q;
    q.appendTail(1);
    q.appendTail(2);

    cout << q.deleteHead() << endl;
    cout << q.deleteHead() << endl;
    q.appendTail(4);
    cout << q.deleteHead() << endl;
    // q.deleteHead();

    CStack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
    cout << s.top() << endl;
    s.pop();
    cout << s.top() << endl;
    s.pop();
    s.pop();
    // s.pop();

    return 0;
}
void netSocketManger::endSocket()
{
    if (!threadSend.joinable()) {//线程已启动
        threadSend.~thread();
        delete m_sendEvent;
        m_sendEvent = NULL;
        
    }
    if (!threadRecive.joinable()) {
        threadRecive.~thread();
    }

    while (!m_sendQueue.IsEmpty()) {
        SocketData *sendData = m_sendQueue.Pop();
        //CC_SAFE_FREE(sendData->body);
        free(sendData);
    }
    
    while (!m_mainQueue.IsEmpty()) {
        SocketData *mainData = m_mainQueue.Pop();
        CC_SAFE_FREE(mainData);
        //CC_SAFE_FREE(mainData->addContent);
    }
    
    if (isConnect) {
        cSocket.Close();
        cSocket.Clean();
        isConnect = false;
    }
    m_isFirst = true;
    m_sendDelegateList.clear();
}
int _tmain(int argc, _TCHAR* argv[])
{
	CQueue<char> queue;

	queue.appendTail('a');
	queue.appendTail('b');
	queue.appendTail('c');

	char head = queue.deleteHead();
	Test(head, 'a');

	head = queue.deleteHead();
	Test(head, 'b');

	queue.appendTail('d');
	head = queue.deleteHead();
	Test(head, 'c');

	queue.appendTail('e');
	head = queue.deleteHead();
	Test(head, 'd');
	
	head = queue.deleteHead();
	Test(head, 'e');

	return 0;
}
Beispiel #5
0
int main()
{
	CQueue *pQueue;
	pQueue = new CQueue();
	fillQueue(pQueue, 3);
	pQueue->printJobs();
	pQueue->pop();
	pQueue->printJobs();
	return 0;
}
Beispiel #6
0
BOOL ConsumeElement(int nThreadNum, int nRequestNum, HWND hWndLB) {

   // Get access to the queue to consume a new element
   AcquireSRWLockShared(&g_srwLock); 

   // Fall asleep until there is something to read.
   // Check if, while it was asleep, 
   // it was not decided that the thread should stop
   while (g_q.IsEmpty(nThreadNum) && !g_fShutdown) {
      // There was not a readable element
      AddText(hWndLB, TEXT("[%d] Nothing to process"), nThreadNum);
         
      // The queue is empty
      // --> Wait until a writer adds a new element to read
      //     and come back with the lock acquired in shared mode
      SleepConditionVariableSRW(&g_cvReadyToConsume, &g_srwLock, 
         INFINITE, CONDITION_VARIABLE_LOCKMODE_SHARED);
   }

   // When thread is exiting, the lock should be released for writer
   // and readers should be signaled through the condition variable
   if (g_fShutdown) {
      // Show that the current thread is exiting
      AddText(hWndLB, TEXT("[%d] bye bye"), nThreadNum);

      // Another writer thread might still be blocked on the lock
      // --> release it before exiting
      ReleaseSRWLockShared(&g_srwLock);

      // Notify other readers that it is time to exit
      // --> release readers
      WakeConditionVariable(&g_cvReadyToConsume);

      return(FALSE);
   }

   // Get the first new element
   CQueue::ELEMENT e;
   // Note: No need to test the return value since IsEmpty
   //       returned FALSE
   g_q.GetNewElement(nThreadNum, e);
      
   // No need to keep the lock any longer
   ReleaseSRWLockShared(&g_srwLock);

   // Show result of consuming the element
   AddText(hWndLB, TEXT("[%d] Processing %d:%d"), 
      nThreadNum, e.m_nThreadNum, e.m_nRequestNum);

   // A free slot is now available for writer threads to produce
   // --> wake up a writer thread
   WakeConditionVariable(&g_cvReadyToProduce);

   return(TRUE);
}
Beispiel #7
0
// blockSize - bytes of each queue item
// nReservedSlots - number of reserved nodes
CQueue* CQueue::Create(CQueue *pMainQ,
                       void *pOwner,
                       AM_UINT blockSize,
                       AM_UINT nReservedSlots)
{
  CQueue *result = new CQueue(pMainQ, pOwner);
  if (result && result->Construct(blockSize, nReservedSlots) != ME_OK) {
    delete result;
    result = NULL;
  }
  return result;
}
int main()
{
	//往空的队列里添加和删除元素
	CQueue cq;
	cq.Push(4);
	cq.Push(5);
	cout << cq.Pop();
	cout << cq.Pop();
	cout << cq.Pop();
	
	return 0;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
}
//接收数据线程
void netSocketManger::reciveThread()
{
    char buff[MAX_BUFF];
    int recv_len = 0;
    bool hasMorePackets = false;
 
    while(true)
    {
        
        if( !hasMorePackets ) {
            
            int ret = cSocket.Recv(buff, MAX_BUFF - recv_len, 0);
            
            if (ret <= 0) {
                isConnect = false;
                SocketData *errorData = newSocketData();
                errorData->eventType = DISCONNECT;
                m_mainQueue.Push(errorData);
                break;
            }
            if(ret < 1)
                break;
        }
       
            T_MSGHEAD_T reciveCmd;
            reciveCmd.len = 1;        //接收缓存中的前64个字节数据
            reciveCmd.enc = 0;        //数据是否加密标志
            reciveCmd.com = 0;        //数据是否压缩标志,这两个我们都设置为否,因为我们的数据本身只有一位
            reciveCmd.idx = (uInt)m_sn;      //包索引也设置为固定值,因为我们只有一个接口,这里发arduino马上就会回.
            reciveCmd.tea = 0;
            unsigned int pos = 0;
            
            SocketData *data = newSocketData();
            data->module.cmd = 100;   //先将100设置为灯的协议号
            data->module.eno = 0;     //主动将错误码设置为0,即正常
            data->eventType = RESPONSE;
            data->sn = reciveCmd.idx;
            std::string datax(&buff[pos],reciveCmd.len);
            data->body = std::string(datax);
            pos += reciveCmd.len;
            data->bodyLen = reciveCmd.len;
        
        log("接收:%s",data->body.c_str());
            log("*************************************************");
            log("*************************************************");
            
            m_mainQueue.Push(data);
            
            hasMorePackets = false;
        
    }
    
}
/*
 * Interrupt handler
 */
void USART4_IRQHandler(void)
{
	static AsyncSerialPort4* portHandle = AsyncSerialPort4::getInstance();
	static CQueue outStream = portHandle->getOutStream();
	static CQueue inStream = portHandle->getInStream();

	portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
	portCHAR cChar;

	if (USART_GetITStatus(UART4, USART_IT_TXE) == SET)
	{
		/* The interrupt was caused by the THR becoming empty.  Are there any
			more characters to transmit? */
		if (outStream.ReceiveFromISR(&cChar, &xHigherPriorityTaskWoken))
		{
			/* A character was retrieved from the queue so can be sent to the
				THR now. */
			USART_SendData(UART4, cChar);

			if (portHandle->getCurrentStatus() == SERIAL_TX_BUFFER_FULL)
			{
				portHandle->setCurrentStatus(SERIAL_OK);
			}
		}
		else
		{
			USART_ITConfig(UART4, USART_IT_TXE, DISABLE);
		}
	}

	if (USART_GetITStatus(UART4, USART_IT_RXNE) == SET)
	{
		cChar = USART_ReceiveData(UART4);

		if (!inStream.SendFromISR(&cChar, &xHigherPriorityTaskWoken))
		{
			portHandle->setCurrentStatus(SERIAL_OVERRUN_ERROR);
		}
	}

	if (USART_GetITStatus(UART4, USART_IT_PE) == SET)
	{
		portHandle->setCurrentStatus(SERIAL_PARITY_ERROR);
	}

	if (USART_GetITStatus(UART4, USART_IT_ORE_RX) == SET)
	{
		portHandle->setCurrentStatus(SERIAL_OVERRUN_ERROR);
	}

	portEND_SWITCHING_ISR(xHigherPriorityTaskWoken );
}
Beispiel #11
0
int main() {
    cout << "Hello, World!" << endl;

    CQueue<string> cQueue;

    cQueue.appendTail( "test1 ");
    cQueue.appendTail( "test2 ");
    cQueue.appendTail( "test3 ");

    for ( int i = 0; i < 2; ++i )
    {
        cout << cQueue.deleteHead() << endl;
    }

    cQueue.appendTail( "test4 ");
    cQueue.appendTail( "test5 ");
    cQueue.appendTail( "test6 ");

    for ( int i = 0; i < 4; ++i )
    {
        cout << cQueue.deleteHead() << endl;
    }

    cout << cQueue.deleteHead() << endl;


    system("PAUSE");
    return 0;
}
Beispiel #12
0
void algo_stack() {
	CQueue<int> queue;
	for (int i = 0; i < 10; i++) {
		queue.appendTail(i);
	}
	std::cout << "Pop:\n";
	for (int i = 0; i < 5; i++) {
		int j = queue.deleteHead();
		std::cout << j << " ";
	}
	std::cout << "\n";
	for (int i = 10; i < 15; i++) {
		queue.appendTail(i);
	}	
}
int netSocketManger::send(NetWorkCommandStruct module, std::string &body, SendDataDelegate *delegate)
{
    if (!delegate ||  !isConnect) {
        return -1;
    }
    
    m_sn++;
    
    m_sendDelegateList[m_sn] = delegate;
    
    SocketData *data = newSocketData();
    data->sn = m_sn;
    
    if (body.empty()) {
        data->body = "";
        data->bodyLen = 0;
    }else {
        int bodyStrLen = (int)body.size();
        //data->body = (char*)malloc(bodyStrLen);
        const char* tmp = body.data();
        data->sendData = (char*)malloc(bodyStrLen);
        memcpy(data->sendData, tmp, bodyStrLen);
        data->bodyLen = bodyStrLen;
    }
    
    data->module.cmd = module.cmd;
    
    m_sendQueue.Push(data);
    
    m_sendEvent->Post();
    
    return (int)m_sn;
}
Beispiel #14
0
void APollQ::StartPolledQueueTasks(CCheckTask *pCheckTask, UBaseType_t nPriority ) {
	static CQueue queue;

	/* Create the queue used by the producer and consumer. */
	queue.Create(pollqQUEUE_SIZE, (UBaseType_t) sizeof(unsigned short));

	/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
	in use.  The queue registry is provided as a means for kernel aware
	debuggers to locate queues and has no purpose if a kernel aware debugger
	is not being used.  The call to vQueueAddToRegistry() will be removed
	by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
	defined to be less than 1. */
	queue.AddToRegistry("Poll_Test_Queue");

	/* Spawn the producer and consumer. */
	static CPollQConsumer consumer(pCheckTask, &queue);
	consumer.Create("QConsNB", pollqSTACK_SIZE, nPriority);
	static CPollQProducer producer(pCheckTask, &queue);
	producer.Create("QProdNB", pollqSTACK_SIZE, nPriority);
}
Beispiel #15
0
int main()
{
    CQueue *queue = new CQueue();
    size_t operation_num = 0;
    size_t operation_type;
    int data;
    int correct_flag = 1;

    cin >> operation_num;
    for ( size_t i = 0; i < operation_num; ++i ) {
        cin >> operation_type;
        cin >> data;
        if ( operation_type == PUSH ) {
            queue->Enqueue( data );
        } else {
            correct_flag *= (queue->Dequeue() == data) ? 1 : 0;
        }
    }
    cout << ( correct_flag ) ? "YES" : "NO";
    return 0;
}
Beispiel #16
0
void ABlockQ::StartBlockingQueueTasks(CCheckTask *pCheckTask, UBaseType_t nPriority) {
	const UBaseType_t uxQueueSize1 = 1, uxQueueSize5 = 5;
	const TickType_t xBlockTime = ( TickType_t ) 1000 / portTICK_PERIOD_MS;
	const TickType_t xDontBlock = ( TickType_t ) 0;

	// Create the first two tasks as described at the top of the file.

	// Create the queue used by the first two tasks to pass the incrementing number.
	static CQueue queue1;
	queue1.Create(uxQueueSize1, (UBaseType_t) sizeof(unsigned short));
	static CBlockQConsumer consumer1Task(pCheckTask, &queue1, &s_sBlockingConsumerCount[0], xBlockTime);
	static CBlockQProducer producer1Task(pCheckTask, &queue1, &s_sBlockingProducerCount[0], xDontBlock);

	//Note the producer has a lower priority than the consumer when the tasks are spawned.
	consumer1Task.Create("QConsB1", blckqSTACK_SIZE, nPriority);
	producer1Task.Create("QProdB2", blckqSTACK_SIZE, tskIDLE_PRIORITY);

	// Create the second two tasks as described at the top of the file. This uses
	// the same mechanism but reverses the task priorities.
	static CQueue queue2;
	queue2.Create(uxQueueSize1, (UBaseType_t) sizeof(unsigned short));
	static CBlockQConsumer consumer2Task(pCheckTask, &queue2, &s_sBlockingConsumerCount[1], xDontBlock);
	static CBlockQProducer producer2Task(pCheckTask, &queue2, &s_sBlockingProducerCount[1], xBlockTime);
	consumer2Task.Create("QProdB3", blckqSTACK_SIZE, tskIDLE_PRIORITY);
	producer2Task.Create("QConsB4", blckqSTACK_SIZE, nPriority);

	// Create the last two tasks as described above.  The mechanism is again just
	// the same.  This time both parameter structures are given a block time.
	static CQueue queue3;
	queue3.Create(uxQueueSize5, (UBaseType_t) sizeof(unsigned short));
	static CBlockQProducer producer3Task(pCheckTask, &queue3, &s_sBlockingProducerCount[2], xBlockTime);
	static CBlockQConsumer consumer3Task(pCheckTask, &queue3, &s_sBlockingConsumerCount[2], xBlockTime);
	producer3Task.Create("QProdB5", blckqSTACK_SIZE, tskIDLE_PRIORITY);
	consumer3Task.Create("QConsB6", blckqSTACK_SIZE, tskIDLE_PRIORITY);
}
Beispiel #17
0
// 添加到等待发送队列中,是否为延后由线程对象来发送,主要触
bool CQueueMgr::Add( const char *id, unsigned int seq, void *data , bool send )
{
	_mutex.lock() ;

	CQueue *p = NULL ;
	CMapQueue::iterator it = _index.find( id ) ;
	if ( it == _index.end() ) {
		p = new CQueue(_pCaller, _maxent ) ;
		p->_id = id ;
		_queue.push( p ) ;
		_index.insert( std::make_pair(id, p ) ) ;
	} else {
		p = it->second ;
	}
	bool success = p->Add( seq, data, _maxspan , send ) ;

	_mutex.unlock() ;

	_monitor.notify() ;

	return success ;
}
Beispiel #18
0
int main(int argc, char **argv)
{
	CHtHif *pHtHif = new CHtHif();
	CHtSuUnitEx *pSuUnit = new CHtSuUnitEx(pHtHif);

	pSuUnit->SetUsingCallback(true);

	int err_cnt = 0;

	uint16_t callCnt = 0;
	int sendDataCnt = 0;

	for (int i = 0; i < ARR_SIZE; i++) {
		memArr[i] = 0x0300 | i;
		sendArr[i] = 0x04000000 | (i << 16);
	}

	pSuUnit->SendHostMsg(SU_ARRAY_ADDR, (uint64_t)&memArr);

	while (callCnt < TEST_CNT || markerCnt < TEST_CNT || rtnCnt < TEST_CNT) {
		if (callCnt < TEST_CNT && sendDataCnt == 0 && pSuUnit->SendCall_echo(callCnt)) {
			sendDataCnt = callCnt++ + 1;
			dataCntQue.Push(sendDataCnt);
			continue;
		}

		if (sendDataCnt > 1) {
			sendDataCnt -= pSuUnit->SendHostData(sendDataCnt - 1, sendArr);
			continue;
		}

		if (sendDataCnt == 1 && pSuUnit->SendHostDataMarker()) {
			sendDataCnt = 0;
			continue;
		}

		if (pSuUnit->RecvPoll() == Ht::eRecvIdle)
			usleep(1000);
	}

	delete pHtHif;

	if (err_cnt)
		printf("FAILED: detected %d issues!\n", err_cnt);
	else
		printf("PASSED\n");

	return err_cnt;
}
int main(){
	CQueue<char> queue;

	queue.appendTail('a');
	queue.appendTail('b');
	queue.appendTail('c');

	cout<<queue.deleteHead()<<queue.deleteHead()<<queue.deleteHead()<<endl;
	return 0;
}
Beispiel #20
0
int main() {
    CQueue<int> aQueue;
    aQueue.appendTail(1);
    aQueue.appendTail(2);
    aQueue.appendTail(3);
    cout << aQueue.deleteHead() << endl;

    aQueue.appendTail(4);
    cout << aQueue.deleteHead() << endl;
    cout << aQueue.deleteHead() << endl;
    cout << aQueue.deleteHead() << endl;

    try {
        aQueue.deleteHead();
    } catch (exception e) {
        cout << e.what() << endl;
    }
    return 0;
}
int main() {
	CQueue<int> cq;
	int a = 1;
	int b = 2;
	int c = 3;
	int d = 4;
	cq.appendTail(a);
	cq.appendTail(b);
	cq.appendTail(c);
	cq.deleteHead();
	cq.appendTail(d);
	cq.deleteHead();
	cq.deleteHead();
	cq.deleteHead();
	cq.deleteHead();
	cq.deleteHead();

	system("pause");
	return 0;
}
Beispiel #22
0
void CHtSuUnitEx::RecvCallback(Ht::ERecvType recvType)
{
	switch (recvType) {
	case Ht::eRecvHostData:
	{
		if (recvDataCnt == 0) {
			assert(!dataCntQue.Empty());
			recvDataCnt = dataCntQue.Front();
			dataCntQue.Pop();
			printf("eRecvHostData - recvDataCnt = %d\n", recvDataCnt);
		}

		assert(recvDataCnt > 1);
		recvDataCnt -= RecvHostData(recvDataCnt - 1, recvArr);
	}
	break;
	case Ht::eRecvHostDataMarker:
	{
		if (recvDataCnt == 0) {
			assert(!dataCntQue.Empty());
			recvDataCnt = dataCntQue.Front();
			dataCntQue.Pop();
			printf("eRecvDataMarker - recvDataCnt = %d\n", recvDataCnt);
		}

		assert(recvDataCnt == 1);
		bool bMarker = RecvHostDataMarker();
		assert(bMarker);
		recvDataCnt = 0;
		markerCnt += 1;
	}
	break;
	case Ht::eRecvReturn:
	{
		uint16_t recvDataCnt;
		RecvReturn_echo(recvDataCnt);
		rtnCnt += 1;
	}
	break;
	default:
		assert(0);
	}
}
//发送数据线程
void netSocketManger::sendThread()
{

    //bool connect = cSocket.Connect(kServerIP,kServerPort);
    bool connect = cSocket.Connect(netSocketManger::sharednetSocketManger()->server.IP.c_str(),netSocketManger::sharednetSocketManger()->server.port);
   // cSocket.Send("bbb",strlen("bbb")+1,0);

    if (connect) {
        isConnect = true;
        SocketData *errorData = newSocketData();
        errorData->eventType = CONNECT_SUCCEED;
        m_mainQueue.Push(errorData);
        //创建接收线程
        m_mutexx.lock();
        netSocketManger::sharednetSocketManger()->createReciveThread();
        m_mutexx.unlock();
        m_sendEvent->Lock();
        while (true) {
            while (!m_sendQueue.IsEmpty()) {
                SocketData *data = m_sendQueue.Pop();
                uLong comprLen = data->bodyLen;
                const char *compr = data->sendData;
                
                T_MSGHEAD_T msgHead;
                
                msgHead.cmd = (unsigned short)data->module.cmd;
                msgHead.com = 0;
                msgHead.enc = 0;
                msgHead.eno = 0;
                msgHead.idx = (uInt)data->sn;
                msgHead.len = (unsigned short)comprLen;
                msgHead.tea = 0;//s_tea;
                
                unsigned char *sendData = (unsigned char*)malloc(comprLen);
                unsigned int pos = 0;
                
                memcpy(&sendData[pos], compr, comprLen);//body
                pos += comprLen;
                
                int ret = cSocket.Send((char*)sendData,pos,0);
                log("发送:%s",compr);
                if (ret <= 0) {
                    m_sendEvent->Unlock();
                    free(sendData);
                    SocketData *errorData = newSocketData();
                    errorData->eventType = DISCONNECT;
                    m_mainQueue.Push(errorData);
                    return;
                }

                free(data->sendData);
                free(data);
                free(sendData);

                log("-----发送数据长度len:%d------",msgHead.len);
                log("-----------");
                
            }
            
            m_sendEvent->Wait();
        }
        m_sendEvent->Unlock();
    }else {
        isConnect = false;
        SocketData *errorData = newSocketData();
        errorData->eventType = CONNECT_FAIL;
        m_mainQueue.Push(errorData);
    }
}
//主线程更新
void netSocketManger::update(float dt)
{
    if (!m_mainQueue.IsEmpty()) {
        SocketData *data = m_mainQueue.Pop();
        
        if (data->eventType == REQUEST) {
            if (m_pushDelegate) {
                m_pushDelegate->pushHandler(data);
            }
        }else if (data->eventType == RESPONSE) {
            SendDelegateMap::iterator it = m_sendDelegateList.find(data->sn);
            if (it != m_sendDelegateList.end()) {
                SendDataDelegate *delegate = it->second;
                m_sendDelegateList.erase(it);
                delegate->sendHandler(data);
            }
        }else if (data->eventType == CONNECT_SUCCEED || data->eventType == CONNECT_FAIL || data->eventType == DISCONNECT) {
            if (data->eventType != CONNECT_SUCCEED) {
                if (!threadSend.joinable()) {//线程已启动
                    threadSend.~thread();
                    delete m_sendEvent;
                    m_sendEvent = NULL;
                    
                }
                if (!threadRecive.joinable()) {
                    threadRecive.~thread();
                }
                
                while (!m_sendQueue.IsEmpty()) {
                    SocketData *sendData = m_sendQueue.Pop();
                    //litaoming update
                    //CC_SAFE_FREE(data->body);
                    //CC_SAFE_FREE(sendData->reciveBody);
                    free(sendData);
                }
                
                while (!m_mainQueue.IsEmpty()) {
                    SocketData *mainData = m_mainQueue.Pop();
                    if (mainData != data) {
                        //CC_SAFE_FREE(mainData->body);
                        //CC_SAFE_FREE(mainData->addContent);
                    }
                    
                }
                if (isConnect) {
                    cSocket.Close();
                    cSocket.Clean();
                    isConnect = false;
                }
                m_isFirst = true;
                m_sendDelegateList.clear();
            }
            if (m_statusDelegate) {
                m_statusDelegate->statusHandler(data->eventType);
            }
        }
        //CC_SAFE_FREE(data->body);
        //CC_SAFE_FREE(data->addContent);
        free(data);
    }
}
Beispiel #25
0
DWORD WINAPI WriterThread(PVOID pvParam) {

   int nThreadNum = PtrToUlong(pvParam);
   HWND hWndLB = GetDlgItem(g_hWnd, IDC_CLIENTS);

   for (int nRequestNum = 1; !g_fShutdown; nRequestNum++) {

      CQueue::ELEMENT e = { nThreadNum, nRequestNum };

      // Require access for writing
      AcquireSRWLockExclusive(&g_srwLock);

      // If the queue is full, fall asleep as long as the condition variable 
      // is not signaled
      // Note: During the wait for acquiring the lock, 
      //       a stop might have been received
      if (g_q.IsFull() & !g_fShutdown) {
         // No more room in the queue
         AddText(hWndLB, TEXT("[%d] Queue is full: impossible to add %d"), 
            nThreadNum, nRequestNum);

         // --> Need to wait for a reader to empty a slot before acquiring 
         //     the lock again 
         SleepConditionVariableSRW(&g_cvReadyToProduce, &g_srwLock, 
            INFINITE, 0);
      }

      // Other writer threads might still be blocked on the lock
      // --> Release the lock and notify the remaining writer threads to quit
      if (g_fShutdown) {
         // Show that the current thread is exiting
         AddText(hWndLB, TEXT("[%d] bye bye"), nThreadNum);

         // No need to keep the lock any longer
         ReleaseSRWLockExclusive(&g_srwLock);

         // Signal other blocked writers threads that it is time to exit
         WakeAllConditionVariable(&g_cvReadyToProduce);

         // Bye bye
         return(0);
      } else {
         // Add the new ELEMENT into the queue
         g_q.AddElement(e);

         // Show result of processing element
         AddText(hWndLB, TEXT("[%d] Adding %d"), nThreadNum, nRequestNum);

         // No need to keep the lock any longer
         ReleaseSRWLockExclusive(&g_srwLock);

         // Signal reader threads that there is an element to consume
         WakeAllConditionVariable(&g_cvReadyToConsume);

         // Wait before adding a new element
         Sleep(1500);
      }
   }

   // Show that the current thread is exiting
   AddText(hWndLB, TEXT("[%d] bye bye"), nThreadNum);

   return(0);
}