Hỏi về thread đồng hồ đếm ngược C++

Em sv năm nhất và có một bài tập lớn làm về game. Trong đó, có một yêu cầu về đồng hồ đếm ngược, nếu đồng hồ về 0 thì không thể nhập giá trị nữa. Em có tham khảo code trên mạng về đồng hồ đếm ngược sử dụng thread. Em muốn hỏi làm cách nào để khi đồng hồ về 0 thì không thể nhập nữa ạ. Mong mn giúp ạ. Em cảm ơn nhiều !!!

năm 1 chắc làm game trên console hả em :V

3 Likes

Vâng ạ. Làm game trên màn hình console ạ

tìm cách xài ncurses nha em :V Trên windows có https://github.com/wmcbrine/PDCurses thay cho ncurses chỉ có trên linux.

nếu xài ncurses thì rất đơn giản:

char line[100];
timeout(5000); // cho 5 giây để nhập
int status = getstr(line); 
if (status == ERR) {
    // quá thời gian
} else {
    // làm gì đó với chuỗi `line`
}

nếu em biết vcpkg thì chỉ cần gọi vcpkg install pdcurses rồi mở VS2015/17/19 lên là tạo project xài vô tư :V :V


còn có cách chơi kbhit và while loop trên windows mà lâu quá anh ko nhớ code để chỗ nào từ từ tìm lại =]

#include <iostream>
#include <conio.h>
#include <windows.h>
#include <ctime>

char timedCharInput(unsigned sec);

int main()
{
    std::cout << "Quick, enter a letter: ";
    char in = timedCharInput(2);
    if (!in) std::cout << "You're too slow.\n";
    else     std::cout << "Your response is " << in << '\n';
}

char timedCharInput(unsigned sec)
{
    clock_t stop = clock() + sec * CLOCKS_PER_SEC;
    char ret = '\0';
    while (clock() <= stop) {
        if (_kbhit()) {
            char c = _getch();
            if (c == '\b' || c == 0x7f) {
                if (ret) std::cout << "\b \b";
                ret = '\0';
            } else if (c == '\r' || c == '\n') {
                std::cout << '\n';
                return ret;
            } else {
                if (ret) std::cout << "\b \b";
                std::cout << c;
                ret = c;
            }
        }
        Sleep(16); // don't rape your CPU!
    }
    std::cout << '\n';
    return '\0';
}

code này chỉ cho input 1 ký tự. Nếu em muốn input 1 chuỗi thì hơi phức tạp vì user có thể xài phím mũi tên qua trái qua phải dời con trỏ tới đủ vị trí :V Thôi để em tự vọc =]

đáng lẽ phải đặt tên hàm timedCharInputcharInputTimeout mới đúng =]

3 Likes

em cảm ơn nhiều ạ. Em sẽ tìm hiểu ạ

Cho e hỏi với ạ:
hàm trên là nhập vào 1 kí tự trong thời gian quy định. vì yêu cầu bài tập khi nhập nhiều lần, mỗi lần nhập phải có đồng hộ đếm ngược trên mh console, vậy nên em tạo 1 thread clock ngay trong hàm nhập nhưng khi chạy được lần nhập đầu tiên nó hiện lỗi : terminate called without an active exception thì làm thế nào để sửa ạ

dòng std::cout << c; thay vì em in ra c em in ra thêm double(clock() - stop) / CLOCKS_PER_SEC là được. Thay std::cout << "\b \b"; bằng std::cout << "\r"; nhưng mà em phải input trên 1 dòng riêng :V

2 Likes

đây em, xài chrono cho nó máu :rofl:

#include <iostream>
#include <conio.h>
#include <windows.h>
#include <string>
#include <chrono>
#include <iomanip>
namespace cron = std::chrono;
using namespace std::literals::chrono_literals;

char charInputTimeout(cron::milliseconds, const std::string&,
                      cron::milliseconds = 1s, int = 0);

int main() {
    while (true) {
        char in = charInputTimeout(5s, "Quick, enter a letter: ", 500ms, 1);
        if (!in) {
            std::cout << "You're too slow.\n";
        } else {
            std::cout << "Your response is " << in << '\n';
            if (in == 'q' || in == 'Q') break;
        }
    }
}

char charInputTimeout(cron::milliseconds duration, const std::string& label,
                      cron::milliseconds displayInterval, int timerPrecision) {
    char ret = 0;
    auto now = cron::steady_clock::now();
    auto timerEnd = now + duration;
    cron::duration<double> timeLeft = timerEnd - now;
    auto lastIntervalDisplayTime = now;
    bool redraw = true;

    while (timeLeft > 0s) {
        // Check if we need to redraw time because of key hit
        if (_kbhit()) {
            char ch = _getch();
            if (ch == '\b' || ch == 0x7f) {
                ret = 0;
                std::cout << "\b \b"; // quick and dirty backspace
                redraw = true;
            } else if (ch == '\r' || ch == '\n') {
                if (ret) break;
                // else do nothing
            } else {
                ret = ch;
                redraw = true;
            }
        }
        // Check if we need to redraw time interval
        now = cron::steady_clock::now();
        timeLeft = timerEnd - now;
        if (timeLeft < 0s) timeLeft = 0s;
        if (now - lastIntervalDisplayTime >= displayInterval) {
            redraw = true;
            lastIntervalDisplayTime = now;
        }
        // Draw
        if (redraw) {
            std::cout << "\rYou have " << std::fixed
                      << std::setprecision(timerPrecision) << timeLeft.count()
                      << "s left. " << label;
            if (ret) std::cout << ret;
            redraw = false;
        }
        Sleep(16); // don't rape your CPU!
    }
    std::cout << '\n';
    return ret;
}

vẫn còn lỗi display cái time left đôi lúc nó hiện ko đúng 2.0 mà nó hiện 1.9 :V

console cùi bắp thì nó giựt giựt như vậy thôi nha em =]

2 Likes

Mình cũng mới làm cái bài tập nhóm cũng gắp rắc rối giống như bạn. Mình dùng socket trong project của mình và cũng cần time out hoặc break nếu user ko muốn đợi lâu. Cái lỗi terminate called without an active exception là do bạn chưa join() hoặc detach() cái thread.

3 Likes

Dạ vâng em cảm ơn ạ.

Z h e join() ngay trong hàm nhập đc ko ạ hay chỉ được join() trong hàm main

#include <iostream>
#include <thread>
#include <conio.h>
#include<Windows.h>

using namespace std;
bool stop = 1;
struct Hour {
	int hour;
	int minute;
	int second;
};

char inToA(int k) {
	switch (k)
	{
	case 0:return '0';
	case 1:return '1';
	case 2:return '2';
	case 3:return '3';
	case 4:return '4';
	case 5:return '5';
	case 6:return '6';
	case 7:return '7';
	case 8:return '8';
	case 9:return '9';
	default:
		break;
	}
}

void insertarray(char *h, Hour *j) {
	int bait = 0;
	bait = j->second;
	h[7] = inToA(bait % 10);
	h[6] = inToA(bait /= 10);

	bait = j->minute;
	h[4] = inToA(bait % 10);
	h[3] = inToA(bait /= 10);

	bait = j->hour;
	h[1] = inToA(bait % 10);
	h[0] = inToA(bait /= 10);

}

bool changetime(Hour *h) {
	if (h->second > 0) --h->second;
	else if (h->minute > 0) {
		h->second = 59;
		--h->minute;
	}
	else if (h->hour > 0)
	{
		--h->hour;
		h->minute = 59;
		h->second = 59;
	}
	else return 0;
	return 1;
}

//dung de in ra mot chuoi thay the ham cout
void WriteBlockChar(char * Arraych,
	int row, int col,
	int x, int y,
	int color)
{
	CHAR_INFO *charater = new CHAR_INFO[row*col];
	for (int i = 0; i < row*col; i++) {
		charater[i].Attributes = color;
		charater[i].Char.AsciiChar = Arraych[i];
	}
	COORD sizebuff = { col,row };
	COORD pos = { 0,0 };
	SMALL_RECT earea = { x,y,x + col - 1,y + row - 1 };
	WriteConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE), charater, sizebuff, pos, &earea);
	delete[] charater;
}

void printClock() {
		Hour h = { 0,0,6 };
		char a[8] = { '0','0',':','0','0',':','0','0'};
		while (stop)
		{
			if (!changetime(&h)) stop = 0;
			insertarray(a, &h);
			WriteBlockChar(a, 1, 8, 70, 3,0x004|0x060);
			Sleep(970);
		}
		return;
}
void gotoXY(int column, int line)
{
	COORD coord;
	coord.X = column;
	coord.Y = line;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

void TextColor(int color)
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}
void close(DWORD evt) {
	if (evt == CTRL_CLOSE_EVENT) stop = 0;
}
char timedCharInput(unsigned sec)
{
    clock_t stop = clock() + sec * CLOCKS_PER_SEC;
    char ret = '\0';
    while (clock() <= stop) {
        if (_kbhit()) {
            char guess = _getch();
            if (guess == '\b' || guess == 0x7f) {
                if (ret) std::cout << "\b \b";
                ret = '\0';
            } else if (guess == '\r' || guess == '\n') {
                std::cout << '\n';
                return ret;
            } else {
                if (ret) std::cout << "\b \b";
                std::cout << guess;
                ret = guess;
            }
        }
        Sleep(16);
    }
    std::cout << '\n';
    return '\0';
}

int main() {
	SetConsoleCtrlHandler((PHANDLER_ROUTINE)close, TRUE);
	thread clock;
	int i = 0;
	for(i;i<10;i++){
    clock = thread(printClock);
	std::cout << "Quick, enter a letter: ";
    char guess = timedCharInput(5);
    if (!guess) std::cout << "You're too slow.\n";
    else     std::cout << "Your response is " << guess << '\n';
	stop = 0;
	clock.join();
	}
	return 0;
}

Ai có thể chỉ em lỗi sai ở đâu đc không ạ? Nó vẫn chỉ đc 1 lần thôi.

em cần gotoxy và textcolor thì thôi xài pdcurses đi :V

1 Like
-------------- Build: Debug in mm (compiler: GNU GCC Compiler)---------------

g++.exe -Wall -fexceptions -g -std=gnu++11 -std=c++11  -c C:\Users\Admin\Documents\mm\main.cpp -o obj\Debug\main.o
g++.exe  -o bin\Debug\mm.exe obj\Debug\main.o   
C:\Users\Admin\Documents\mm\main.cpp:8:22: error: 'std::literals' has not been declared
 using namespace std::literals::chrono_literals;
                      ^~~~~~~~
C:\Users\Admin\Documents\mm\main.cpp:8:32: error: 'chrono_literals' is not a namespace-name
 using namespace std::literals::chrono_literals;
                                ^~~~~~~~~~~~~~~
C:\Users\Admin\Documents\mm\main.cpp:8:47: error: expected namespace-name before ';' token
 using namespace std::literals::chrono_literals;
                                               ^
C:\Users\Admin\Documents\mm\main.cpp:11:44: error: unable to find numeric literal operator 'operator""s'
                       cron::milliseconds = 1s, int = 0);
                                            ^~
C:\Users\Admin\Documents\mm\main.cpp:11:44: note: use -fext-numeric-literals to enable more built-in suffixes
C:\Users\Admin\Documents\mm\main.cpp: In function 'int main()':
C:\Users\Admin\Documents\mm\main.cpp:15:36: error: unable to find numeric literal operator 'operator""s'
         char in = charInputTimeout(5s, "Quick, enter a letter: ", 500ms, 1);
                                    ^~
C:\Users\Admin\Documents\mm\main.cpp:15:36: note: use -fext-numeric-literals to enable more built-in suffixes
C:\Users\Admin\Documents\mm\main.cpp:15:67: error: unable to find numeric literal operator 'operator""ms'
         char in = charInputTimeout(5s, "Quick, enter a letter: ", 500ms, 1);
                                                                   ^~~~~
C:\Users\Admin\Documents\mm\main.cpp:15:67: note: use -fext-numeric-literals to enable more built-in suffixes
C:\Users\Admin\Documents\mm\main.cpp: In function 'char charInputTimeout(std::chrono::milliseconds, const string&, std::chrono::milliseconds, int)':
C:\Users\Admin\Documents\mm\main.cpp:34:23: error: unable to find numeric literal operator 'operator""s'
     while (timeLeft > 0s) {
                       ^~
C:\Users\Admin\Documents\mm\main.cpp:34:23: note: use -fext-numeric-literals to enable more built-in suffixes
C:\Users\Admin\Documents\mm\main.cpp:53:24: error: unable to find numeric literal operator 'operator""s'
         if (timeLeft < 0s) timeLeft = 0s;
                        ^~
C:\Users\Admin\Documents\mm\main.cpp:53:24: note: use -fext-numeric-literals to enable more built-in suffixes
C:\Users\Admin\Documents\mm\main.cpp:53:39: error: unable to find numeric literal operator 'operator""s'
         if (timeLeft < 0s) timeLeft = 0s;
                                       ^~
C:\Users\Admin\Documents\mm\main.cpp:53:39: note: use -fext-numeric-literals to enable more built-in suffixes
Process terminated with status 1 (0 minute(s), 2 second(s))
9 error(s), 0 warning(s) (0 minute(s), 2 second(s))

em chạy thử code của a nó hiện những lỗi này là sao ạ

@DuongBinh26082001
Bạn nên đọc:

1 Like

em cần include thêm thư viện <chrono> nữa :V

ko cần tới thread đâu.Cái em cần là non-blocking I/O :V Xài thread mà xài blocking i/o của cin thì cũng như ko :V

3 Likes

em có #includer ạ mà vẫn ko đc. Nó vẫn báo lỗi ạ.

à chrono_literals thì C++14 mới có :sweat_smile: Hiện tại em đang xài C++11, em vào chỉnh compiler của em lại xài C++14 ấy.

2 Likes

chạy được r ạ. em cảm ơn. em sẽ sửa lại code để phù hợp với yêu cầu bài tập ạ. Em cảm ơn nhiều ạ

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?