Encountering issues with std::mutex and std::thread - c++

I am encountering issues with both std::thread and std::mutex, unable to get both to play nicely with each other. I've been pulling my hair out over this for the past few hours and just cannot make any progress whatsoever. I believe it is out of my skill area. The code is just below:
void GekkoFyre::TuiHangouts::gui_userRosterListNav(std::shared_ptr<WINDOW> display,
std::vector<const char *> userList,
const short &menuItem)
{
while (rosterEnabled) {
for (short i = 0; i < totalMenuItems; ++i) {
short diff = (menuItem - i);
if (i < numMenuItems) {
if (i == menuItem) {
size_t msgLen = strlen(userList.at(i));
size_t l = 0;
if (msgLen > subMaxX) {
for (l = subMaxX; l < msgLen; ++l) {
// Scroll the message from left to right, then vice versa, so that it fits within
// the designated window.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
rosterListMutex.lock();
wattron(usrSubWin.get(), A_REVERSE); // Highlight selection
const char *msg = userList.at(i);
mvwaddstr(usrSubWin.get(), i, 0, &msg[(msgLen - l)]);
wrefresh(usrSubWin.get());
touchwin(usrSubWin.get());
rosterListMutex.unlock();
}
} else {
rosterListMutex.lock();
wattron(usrSubWin.get(), A_REVERSE); // Highlight selection
mvwaddstr(usrSubWin.get(), i, 0, userList.at(i));
wrefresh(usrSubWin.get());
touchwin(usrSubWin.get());
rosterListMutex.unlock();
}
}
wattroff(usrSubWin.get(), A_REVERSE); // Remove highlight
if ((i + 1) < numMenuItems) {
mvwaddstr(usrSubWin.get(), (i + 1), 0, userList.at((i + 1)));
}
} else if (diff < (totalMenuItems - numMenuItems) && diff > 0) {
// Allow the scrolling of a username list, from downwards and then back upwards, so that
// the user may see the list in its entirety.
wclear(usrSubWin.get());
int pos = 0;
for (short c = diff; c < (numMenuItems + diff); ++c) {
++pos;
mvwaddstr(usrSubWin.get(), pos, 0, userList.at(c));
}
pos = 0;
break;
}
}
rosterListMutex.lock();
wattroff(usrSubWin.get(), A_REVERSE); // Remove highlight
touchwin(usrSubWin.get());
wrefresh(usrSubWin.get());
wrefresh(display.get());
rosterListMutex.unlock();
}
}
I am trying to display a list of users to the left of a chat window in NCurses, as can be seen in [ 1 ] below, albeit without any users present in said screenshot. I want to keep my privacy :) What happens is that as you scroll down the list, flickering begins to occur back and forth between two usernames after scrolling past just a few. They keep repeatedly selecting each other, just over and over. I believe this is reason of the threads not syncing up properly. The function is implemented as so:
[ 1 ] - http://imgur.com/ZZlFHg2
#define WIDGET_USERS_LIST 1
short menuItem = 0;
int ch = 0;
int curr_widget = 0;
std::thread rosterListNav1(&GekkoFyre::TuiHangouts::gui_userRosterListNav, this, userListWin, rosterFormatted, menuItem);
rosterListNav1.detach();
while ((ch = wgetch(display.get())) != KEY_F(12)) {
switch (ch) {
case KEY_DOWN:
if (curr_widget == WIDGET_USERS_LIST && rosterEnabled) {
++menuItem;
if (menuItem > totalMenuItems - 1) {
menuItem = 0;
}
}
break;
case KEY_UP:
if (curr_widget == WIDGET_USERS_LIST && rosterEnabled) {
--menuItem;
if (menuItem < 0) {
menuItem = totalMenuItems - 1;
}
}
}
std::thread rosterListNav2(&GekkoFyre::TuiHangouts::gui_userRosterListNav, this, userListWin, rosterFormatted, menuItem);
rosterListNav2.detach();
}
Any help on this issue would be dearly appreciated, and I believe I have placed the std::mutex's in the right areas. I am really stumped with this problem. Also beware that while I know a few tricks of the trade, I am entirely self-taught. Some of the nomenclature that is normal to programmers who have gone through university is completely unintelligible to me.

Related

SFML Button Not Working

Under my button class, I have this function that checks if the mouse is within the bounds of the button:
bool Button::isMouseOver(int mousePosX, int mousePosY) {
if (button.getPosition().x < mousePosX &&
button.getPosition().x + button.getSize().x > mousePosX &&
button.getPosition().y < mousePosY &&
button.getPosition().y + button.getSize().y > mousePosY) {
return true;
}
return false;
}
And then under my main cpp file I have this logic used to activate the function:
int mousePosX = sf::Mouse::getPosition().x;
int mousePosY = sf::Mouse::getPosition().y;
switch (Event.type) {
case sf::Event::Closed:
window.close();
case sf::Event::MouseButtonPressed:
if (btnPlay.isMouseOver(mousePosX, mousePosY)) {
std::cout << "True\n";
}
}
but for some reason, nothing happens. And I know that this can work, because I have the same exact code in one of my other games and it works fine.
Slightly off topic, you comment
And I know that this can work, because I have the same exact code in
one of my other games and it works fine.
triggered me to think You might want to consider generalizing this and making something like
bool IsInside(windowPos wp, windowSize ws, someOtherPos sop) {
if (wp.x < sop.X &&
wp.x + ws.x > sop.X &&
wp.y < sop.Y &&
wp.y + ws.y > sop.Y) {
return true;
}
return false;
}
bool Button::isMouseOver(Vector2i mousePos) {
return IsInside(getPosition(), getSize(), mousePos) ;
}
Note types in IsInside are not exact and might actually be the same ( Vector2i ).
This also makes testing easier for correctness and removes a source of errors with copied code.

Pops / clicks when stopping and starting DirectX sound synth in C++ / MFC

I have made a soft synthesizer in Visual Studio 2012 with C++, MFC and DirectX. Despite having added code to rapidly fade out the sound I am experiencing popping / clicking when stopping playback (also when starting).
I copied the DirectX code from this project: http://www.codeproject.com/Articles/7474/Sound-Generator-How-to-create-alien-sounds-using-m
I'm not sure if I'm allowed to cut and paste all the code from the Code Project. Basically I use the Player class from that project as is, the instance of this class is called m_player in my code. The Stop member function in that class calls the Stop function of LPDIRECTSOUNDBUFFER:
void Player::Stop()
{
DWORD status;
if (m_lpDSBuffer == NULL)
return;
HRESULT hres = m_lpDSBuffer->GetStatus(&status);
if (FAILED(hres))
EXCEP(DirectSoundErr::GetErrDesc(hres), "Player::Stop GetStatus");
if ((status & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING)
{
hres = m_lpDSBuffer->Stop();
if (FAILED(hres))
EXCEP(DirectSoundErr::GetErrDesc(hres), "Player::Stop Stop");
}
}
Here is the notification code (with some supporting code) in my project that fills the sound buffer. Note that the rend function always returns a double between -1 to 1, m_ev_smps = 441, m_n_evs = 3 and m_ev_sz = 882. subInit is called from OnInitDialog:
#define FD_STEP 0.0005
#define SC_NOT_PLYD 0
#define SC_PLYNG 1
#define SC_FD_OUT 2
#define SC_FD_IN 3
#define SC_STPNG 4
#define SC_STPD 5
bool CMainDlg::subInit()
// initialises various variables and the sound player
{
Player *pPlayer;
SOUNDFORMAT format;
std::vector<DWORD> events;
int t, buf_sz;
try
{
pPlayer = new Player();
pPlayer->SetHWnd(m_hWnd);
m_player = pPlayer;
m_player->Init();
format.NbBitsPerSample = 16;
format.NbChannels = 1;
format.SamplingRate = 44100;
m_ev_smps = 441;
m_n_evs = 3;
m_smps = new short[m_ev_smps];
m_smp_scale = (int)pow(2, format.NbBitsPerSample - 1);
m_max_tm = (int)((double)m_ev_smps / (double)(format.SamplingRate * 1000));
m_ev_sz = m_ev_smps * format.NbBitsPerSample/8;
buf_sz = m_ev_sz * m_n_evs;
m_player->CreateSoundBuffer(format, buf_sz, 0);
m_player->SetSoundEventListener(this);
for(t = 0; t < m_n_evs; t++)
events.push_back((int)((t + 1)*m_ev_sz - m_ev_sz * 0.95));
m_player->CreateEventReadNotification(events);
m_status = SC_NOT_PLYD;
}
catch(MATExceptions &e)
{
MessageBox(e.getAllExceptionStr().c_str(), "Error initializing the sound player");
EndDialog(IDCANCEL);
return FALSE;
}
return TRUE;
}
void CMainDlg::Stop()
// stop playing
{
m_player->Stop();
m_status = SC_STPD;
}
void CMainDlg::OnBnClickedStop()
// causes fade out
{
m_status = SC_FD_OUT;
}
void CMainDlg::OnSoundPlayerNotify(int ev_num)
// render some sound samples and check for errors
{
ScopeGuardMutex guard(&m_mutex);
int s, end, begin, elapsed;
if (m_status != SC_STPNG)
{
begin = GetTickCount();
try
{
for(s = 0; s < m_ev_smps; s++)
{
m_smps[s] = (int)(m_synth->rend() * 32768 * m_fade);
if (m_status == SC_FD_IN)
{
m_fade += FD_STEP;
if (m_fade > 1)
{
m_fade = 1;
m_status = SC_PLYNG;
}
}
else if (m_status == SC_FD_OUT)
{
m_fade -= FD_STEP;
if (m_fade < 0)
{
m_fade = 0;
m_status = SC_STPNG;
}
}
}
}
catch(MATExceptions &e)
{
OutputDebugString(e.getAllExceptionStr().c_str());
}
try
{
m_player->Write(((ev_num + 1) % m_n_evs)*m_ev_sz, (unsigned char*)m_smps, m_ev_sz);
}
catch(MATExceptions &e)
{
OutputDebugString(e.getAllExceptionStr().c_str());
}
end = GetTickCount();
elapsed = end - begin;
if(elapsed > m_max_tm)
m_warn_msg.Format(_T("Warning! compute time: %dms"), elapsed);
else
m_warn_msg.Format(_T("compute time: %dms"), elapsed);
}
if (m_status == SC_STPNG)
Stop();
}
It seems like the buffer is not always sounding out when the stop button is clicked. I don't have any specific code for waiting for the sound buffer to finish playing before the DirectX Stop is called. Other than that the sound playback is working just fine, so at least I am initialising the player correctly and notification code is working in that respect.
Try replacing 32768 with 32767. Not by any means sure this is your issue, but it could overflow the positive short int range (assuming your audio is 16-bit) and cause a "pop".
I got rid of the pops / clicks when stopping playback, by filling the buffer with zeros after the fade out. However I still get pops when re-starting playback, despite filling with zeros and then fading back in (it is frustrating).

GIF LZW decompression

I am trying to implement a simple Gif-Reader in c++.
I currently stuck with decompressing the Imagedata.
If an image includes a Clear Code my decompression algorithm fails.
After the Clear Code I rebuild the CodeTable reset the CodeSize to MinimumLzwCodeSize + 1.
Then I read the next code and add it to the indexstream. The problem is that after clearing, the next codes include values greater than the size of the current codetable.
For example the sample file from wikipedia: rotating-earth.gif has a code value of 262 but the GlobalColorTable is only 256. How do I handle this?
I implemented the lzw decompression according to gif spec..
here is the main code part of decompressing:
int prevCode = GetCode(ptr, offset, codeSize);
codeStream.push_back(prevCode);
while (true)
{
auto code = GetCode(ptr, offset, codeSize);
//
//Clear code
//
if (code == IndexClearCode)
{
//reset codesize
codeSize = blockA.LZWMinimumCodeSize + 1;
currentNodeValue = pow(2, codeSize) - 1;
//reset codeTable
codeTable.resize(colorTable.size() + 2);
//read next code
prevCode = GetCode(ptr, offset, codeSize);
codeStream.push_back(prevCode);
continue;
}
else if (code == IndexEndOfInformationCode)
break;
//exists in dictionary
if (codeTable.size() > code)
{
if (prevCode >= codeTable.size())
{
prevCode = code;
continue;
}
for (auto c : codeTable[code])
codeStream.push_back(c);
newEntry = codeTable[prevCode];
newEntry.push_back(codeTable[code][0]);
codeTable.push_back(newEntry);
prevCode = code;
if (codeTable.size() - 1 == currentNodeValue)
{
codeSize++;
currentNodeValue = pow(2, codeSize) - 1;
}
}
else
{
if (prevCode >= codeTable.size())
{
prevCode = code;
continue;
}
newEntry = codeTable[prevCode];
newEntry.push_back(codeTable[prevCode][0]);
for (auto c : newEntry)
codeStream.push_back(c);
codeTable.push_back(newEntry);
prevCode = codeTable.size() - 1;
if (codeTable.size() - 1 == currentNodeValue)
{
codeSize++;
currentNodeValue = pow(2, codeSize) - 1;
}
}
}
Found the solution.
It is called Deferred clear code. So when I check if the codeSize needs to be incremented I also need to check if the codeSize is already max(12), as it is possible to to get codes that are of the maximum Code Size. See spec-gif89a.txt.
if (codeTable.size() - 1 == currentNodeValue && codeSize < 12)
{
codeSize++;
currentNodeValue = (1 << codeSize) - 1;
}

Can Allegro update the number of joysticks at runtime?

Is there a way to update the number of joysticks plugged in at run-time other than constantly calling remove_joystick() then install_joystick? This proves to be extremely slow (goes from 60 FPS to around 5).
Allegro 4.2 answers only please...
void Joystick::Update() {
//If joystick input was lost, attempt to reacquire.
if(GetNumJoysticks() == 0) {
throw InputNotAvailableException("Joystick");
}
//If all joysticks were deleted remove input and do nothing.
if(_numjoysticks == 0) {
remove_joystick();
return;
}
//Update state information
if(poll_joystick() < 0) {
throw InputNotAvailableException("Joystick");
}
for(int i = 0; i < _numButtons; ++i) {
_prevButtons[i].b = _curButtons[i].b;
_prevButtons[i].name = _curButtons[i].name;
_curButtons[i].b = joy[_joyNumber].button[i].b;
_curButtons[i].name = joy[_joyNumber].button[i].name;
}
for(int i = 0; i < _numSticks; ++i) {
for(int j = 0; j < joy[_joyNumber].stick[i].num_axis; ++j) {
_prevSticks[i].axis[j].name = _curSticks[i].axis[j].name;
_prevSticks[i].axis[j].pos = _curSticks[i].axis[j].pos;
_prevSticks[i].axis[j].d1 = _curSticks[i].axis[j].d1;
_prevSticks[i].axis[j].d2 = _curSticks[i].axis[j].d2;
_curSticks[i].axis[j].name = joy[_joyNumber].stick[i].axis[j].name;
_curSticks[i].axis[j].pos = joy[_joyNumber].stick[i].axis[j].pos;
_curSticks[i].axis[j].d1 = joy[_joyNumber].stick[i].axis[j].d1;
_curSticks[i].axis[j].d2 = joy[_joyNumber].stick[i].axis[j].d2;
}
_prevSticks[i].flags = _curSticks[i].flags;
_prevSticks[i].name = _curSticks[i].name;
_curSticks[i].flags = joy[_joyNumber].stick[i].flags;
_curSticks[i].name = joy[_joyNumber].stick[i].name;
}
}
int Joystick::GetNumJoysticks() {
remove_joystick();
if(install_joystick(JOY_TYPE_DIRECTX)) {
return 0;
}
return (num_joysticks);
}
The 4.x series does not. The 5.x series does.
You'll have to either listen for native OS events using custom platform specific code (assuming such things exist) and only call the Allegro deinit/init functions when a change is detected, or require the user to initiate joystick refresh manually.
Under Linux, you could inotify_add_watch() /dev/input to check for changes. Looking at the 4.4 Allegro code, looks like you'd want to call the Win32 functions joyGetNumDevs() and joyGetPos(). Something like:
int WIN_MAX_JOYSTICKS = joyGetNumDevs(); // this should never change
JOYINFO ji;
int pluggedin_count = 0;
for (int i = 0; i < WIN_MAX_JOYSTICKS; ++i)
if (joyGetPos(i, &ji) == JOYERR_NOERROR) ++pluggedin_count;
if (pluggedin_count != last_pluggedin_count) /* reinit Allegro */
You'd have to do that every N seconds.
Those joy* functions are Windows functions, so read MSDN docs to learn how to use them.

Sending Key Presses with Interception

I have tried all the normal methods of faking keyboard actions (SendInput/SendKeys/etc) but none of them seemed to work for games that used DirectInput. After a lot of reading and searching I stumbled across Interception, which is a C++ Library that allows you to hook into your devices.
It has been a very long time since I worked with C++ (Nothing existed for C#) so I am having some trouble with this. I have pasted in the sample code below.
Does it look like there would be anyway to initiate key actions from the code using this? The samples all just hook into the devices and rewrite actions (x key prints y, inverts mouse axis, etc).
enum ScanCode
{
SCANCODE_X = 0x2D,
SCANCODE_Y = 0x15,
SCANCODE_ESC = 0x01
};
int main()
{
InterceptionContext context;
InterceptionDevice device;
InterceptionKeyStroke stroke;
raise_process_priority();
context = interception_create_context();
interception_set_filter(context, interception_is_keyboard, INTERCEPTION_FILTER_KEY_DOWN | INTERCEPTION_FILTER_KEY_UP);
/*
for (int i = 0; i < 10; i++)
{
Sleep(1000);
stroke.code = SCANCODE_Y;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
}
*/
while(interception_receive(context, device = interception_wait(context), (InterceptionStroke *)&stroke, 1) > 0)
{
if(stroke.code == SCANCODE_X) stroke.code = SCANCODE_Y;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
if(stroke.code == SCANCODE_ESC) break;
}
The code I commented out was something I tried that didn't work.
You need to tweak key states for UP and DOWN states to get key presses. Pay attention at the while loop that the variable device is returned by interception_wait, your commented out code would send events to what?? device is not initialized! Forget your code and try some more basic. Look at the line inside the loop with the interception_send call, make more two calls after it, but don't forget to change stroke.state before each call using INTERCEPTION_KEY_DOWN and INTERCEPTION_KEY_UP so that you fake down and up events. You'll get extra keys at each keyboard event.
Also, you may try use INTERCEPTION_FILTER_KEY_ALL instead of INTERCEPTION_FILTER_KEY_DOWN | INTERCEPTION_FILTER_KEY_UP. The arrow keys may be special ones as mentioned at the website.
void ThreadMethod()
{
while (true)
{
if (turn)
{
for (int i = 0; i < 10; i++)
{
Sleep(1000);
InterceptionKeyStroke stroke;
stroke.code = SCANCODE_Y;
stroke.state = 0;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
Sleep(1);
stroke.state = 1;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
turn = false;
}
}
else Sleep(1);
}
}
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadMethod, NULL, NULL, NULL);
while (interception_receive(context, device = interception_wait(context), (InterceptionStroke*)&stroke, 1) > 0)
{
if (stroke.code == SCANCODE_F5) turn = true;
interception_send(context, device, (InterceptionStroke*)&stroke, 1);
if (stroke.code == SCANCODE_ESC) break;
}