Win32 Events -- I need to be notified when the event is cleared - multithreading

Win 7, x64, Visual Studio Community 2015, C++
I have a thread which I need to pause/unpause or terminate, which I currently do with manually-reset "run" or "kill" events. The loop in the thread pauses each time for 5000ms.
My goal is to be able to stop waiting or kill the thread while in the middle of the wait.
The problem is the way I currently have it set up, I need to be notified when the "run" event goes to the non-signalled state, but there is no way to do this, unless I create an event with the inverted polarity, but this seems like a kludge. In short, I need a level-sensitive signal, not edge sensitive.
Maybe the event should just toggle the run state?
This is the thread function:
DWORD WINAPI DAQ::_fakeOutFn(void *param) {
DAQ *pThis = (DAQ *)param;
const DWORD timeout = 5000;
bool running = false;
HANDLE handles[] = { pThis->hFakeTaskRunningEvent, pThis->hFakeTaskKillEvent };
do {
DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
switch (result) {
case WAIT_OBJECT_0: // Run started or continued
running = true;
pThis->outputIndex++;
if (pThis->outputIndex >= pThis->numSamples)
pThis->outputIndex = 0;
// Wait here
// Not sure how to cancel this if the TaskRunningEvent goes false during the wait
DWORD result2 = WaitForMultipleObjects(2, handles, FALSE, timeout);
// Check result2, and 'continue' the loop if hFakeTaskRunningEvent went to NON-SIGNALLED state
break;
case WAIT_OBJECT_0 + 1: // Kill requested
running = false;
break;
default:
_ASSERT_EXPR(FALSE, L"Wait error");
break;
}
} while (running);
return 0;
}

Use separate events for the running and resume states. Then you can reset the resume event to pause, and signal the event to resume. The running event should be used to let the thread know when it has work to do, not when it should pause that work for a period of time.
DWORD WINAPI DAQ::_fakeOutFn(void *param)
{
DAQ *pThis = (DAQ *)param;
bool running = false;
HANDLE handles[] = { pThis->hFakeTaskRunningEvent, pThis->hFakeTaskKillEvent };
do
{
DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
switch (result)
{
case WAIT_OBJECT_0: // Run started
{
running = true;
pThis->outputIndex++;
if (pThis->outputIndex >= pThis->numSamples)
pThis->outputIndex = 0;
// check for pause here
HANDLE handles2[] = { pThis->hFakeTaskResumeEvent, pThis->hFakeTaskKillEvent };
DWORD result2 = WaitForMultipleObjects(2, handles2, FALSE, INFINITE);
switch (result2)
{
case WAIT_OBJECT_0;
break;
case WAIT_OBJECT_0 + 1: // Kill requested
running = false;
break;
default:
_ASSERT_EXPR(FALSE, L"Wait error");
break;
}
if (!running) break;
// continue working...
break;
}
case WAIT_OBJECT_0 + 1: // Kill requested
running = false;
break;
default:
_ASSERT_EXPR(FALSE, L"Wait error");
break;
}
}
while (running);
return 0;
}

here i be use not Events, but queue Apc to this thread with 'command' (run,pause,exit). however need know more about task, for select best solution. you writing service ?
struct DAQ
{
HANDLE _hEvent;
enum STATE {
running,
paused,
exit
} _state;
DAQ()
{
_hEvent = 0;
}
~DAQ()
{
if (_hEvent)
{
ZwClose(_hEvent);
}
}
NTSTATUS Init()
{
return ZwCreateEvent(&_hEvent, EVENT_ALL_ACCESS, 0, NotificationEvent, FALSE);
}
void Close()
{
if (HANDLE hEvent = InterlockedExchangePointer(&_hEvent, 0))
{
ZwClose(hEvent);
}
}
DWORD fakeOutFn()
{
DbgPrint("running\n");
_state = running;
ZwSetEvent(_hEvent, 0);
static LARGE_INTEGER Interval = { 0, MINLONG };
do ; while (0 <= ZwDelayExecution(TRUE, &Interval) && _state != exit);
DbgPrint("exit\n");
return 0;
}
static DWORD WINAPI _fakeOutFn(PVOID pThis)
{
return ((DAQ*)pThis)->fakeOutFn();
}
void OnApc(STATE state)
{
_state = state;
static PCSTR stateName[] = { "running", "paused" };
if (state < RTL_NUMBER_OF(stateName))
{
DbgPrint("%s\n", stateName[state]);
}
}
static void WINAPI _OnApc(PVOID pThis, PVOID state, PVOID)
{
((DAQ*)pThis)->OnApc((STATE)(ULONG_PTR)state);
}
};
void test()
{
DAQ d;
if (0 <= d.Init())
{
if (HANDLE hThread = CreateThread(0, 0, DAQ::_fakeOutFn, &d, 0, 0))
{
if (STATUS_SUCCESS == ZwWaitForSingleObject(d._hEvent, FALSE, 0))// need for not QueueApc too early. in case ServiceMain this event not need
{
d.Close();
int n = 5;
do
{
DAQ::STATE state;
if (--n)
{
state = (n & 1) != 0 ? DAQ::running : DAQ::paused;
}
else
{
state = DAQ::exit;
}
ZwQueueApcThread(hThread, DAQ::_OnApc, &d, (PVOID)state, 0);
} while (n);
}
ZwWaitForSingleObject(hThread, FALSE, 0);
ZwClose(hThread);
}
}
}

Related

Futex Error in C application that is using mutex and epoll

I am running epoll to process network connection. Everything is working perfectly I think.
Now i am trying to connect to the Postgresql Database from the child process. I have 4 child process.
Sometimes when i try to connect to the server. It hangs.
Sometimes i get this error
fserver: tpp.c:84: __pthread_tpp_change_priority: Assertion `new_prio
Would appreciate it if someone would be able to advice on my code. Thanks
If i remove the Postgresql Connection code , the problem disappears.
/******CHILD PROCESS **************/
void childProcess()
{
const char conninfo[] = "postgresql://postgres#localhost?port=5432&dbname=ram&password=xxx";
PGconn *conn = PQconnectdb(conninfo);
const ConnStatusType connStatusType = PQstatus(conn);
if (connStatusType == CONNECTION_BAD) {
printf("pg connection not OK");
if (conn) {
PQfinish(conn);
}
exit(1);
} else {
printf("pg connection OK");
}
int efd = epoll_create1(0);
if(efd == -1)
{
perror("Epoll Creation Failed\n");
}
nonblocksocket(&p2c_var);
struct epoll_event event0;
event0.data.fd = p2c_var;
event0.events = EPOLLIN | EPOLLET;
if(epoll_ctl(efd,EPOLL_CTL_ADD,p2c_var,&event0) == -1)
{
perror("First Failed to add file descriptor to epoll watch list\n");
}
nonblocksocket(&c2p_var);
struct epoll_event event1;
event1.data.fd = c2p_var;
event1.events = EPOLLOUT | EPOLLET;
if(epoll_ctl(efd,EPOLL_CTL_ADD,c2p_var,&event1) == -1)
{
perror("Second Failed to add file descriptor to epoll watch list\n");
}
struct epoll_event *ttlevents;
ttlevents = calloc(MAXEVENTS, sizeof(event0));
int head = 0,tail = 0;
pthread_mutex_t buflock;
pthread_mutex_t fdlock;
int bufhead=0,buftail=0;
struct fifoarr *fifoptr = (struct fifoarr *) calloc(QSIZE,sizeof(struct fifoarr));
int co = 0;
char st[1050];
memset(st,0,sizeof(st));
st[0] = 1;
while(1)
{
int eventcount = epoll_wait(efd,ttlevents,MAXEVENTS,-1);
for(int i =0;i<eventcount;i++)
{
if ((ttlevents[i].events & EPOLLERR) || (ttlevents[i].events & EPOLLHUP))
{
/* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */
fprintf (stderr, "epoll error\n");
close (ttlevents[i].data.fd);
continue;
}
if(ttlevents[i].events & EPOLLOUT)
{
if(ttlevents[i].data.fd == c2p_var)
{
pthread_mutex_lock(&buflock);
int bufval = popfd(&bufhead,&buftail);
if(bufval != -1)
{
write(c2p_var,fifoptr[bufval].buffer,sizeof(fifoptr[bufval].buffer));
}
pthread_mutex_unlock(&buflock);
}
}
if(ttlevents[i].events & EPOLLIN)
{
if(ttlevents[i].data.fd == p2c_var)
{
char buffer[1050];
while(1)
{
memset(buffer,0,sizeof(buffer));
int c = read(ttlevents[i].data.fd,buffer,sizeof(buffer));
if(c == -1)
{
if(errno == EAGAIN)
{
printf("Completed Reading From Parent Process\n");
break;
}
}
if(c == 0)
{
printf("Parent terminated Connection.\n");
break;
}
if(buffer[0] != 1)
{
pthread_mutex_lock(&buflock);
int bufval = pushfd(&bufhead);
if(bufval != -1)
{ memset(fifoptr[bufval].buffer,0,sizeof(fifoptr[bufval].buffer)); memcpy(fifoptr[bufval].buffer,buffer,sizeof(buffer));
// processRequest(fifoptr[bufval].buffer,conn);
write(c2p_var,&st,sizeof(st));
}
pthread_mutex_unlock(&buflock);
}//buffer[0]
}//While
}
}//if epollin
} //for
}//while(1)
PQfinish(conn);
}
The program tends to hang.
Well it is working now.
It seems that mutex is the cause of the problem.
Thanks for all that looked at my code.

c++11 update pthread based code to std::thread or boost::thread

I have the following code that I would like to update to be more portable and c++11 friendly. However, I'm stuck as how to replace the pthread calls. I can use std::this_thread::get_id() to get the thread id but can't tell if that thread is still alive.
pthread_t activeThread = 0;
pthread_t getCurrentThread() {
return pthread_self();
}
bool isActiveThreadAlive() {
if(activeThread == 0) {
return false;
}
return pthread_kill(activeThread, 0) != ESRCH;
}
Potential std::thread version...
std::thread::id activeThread = std::thread::id();
std::thread::id getCurrentThread() {
return std::this_thread::get_id();
}
bool isActiveThreadAlive() {
if(activeThread == std::thread::id()) {
return false;
}
return pthread_kill(activeThread, 0) != ESRCH;// <--- need replacement!!!
}
What the code really needs to do is know if the thread has died from an exception or some other error that caused it to terminate without releasing the object. As in the following...
std::unique_lock<std::mutex> uLock = getLock();
while (activeThread != 0) {
if (threadWait.wait_for(uLock, std::chrono::seconds(30)) == std::cv_status::timeout) {
if (!isActiveThreadAlive()) {
activeThread = 0;
}
}
}
activeThread = getCurrentThread();
uLock.unlock();
try {
// do stuff here.
}
catch (const std::exception&) {
}
uLock.lock();
activeThread = 0;
And before anyone asks I do not have a guarantee of control over when, where or how the threads are created. The threads that call the functions may be from anywhere.

DoModal in critical section

in an parallel loop, there is a critical section. I try to execute an mfc dialog with DoModal in the critical section, however since main thread waits for parallel threads, there is no way for my dialog to show up and execute. In order to break this dependency, I create an executable and I run it as a process within my parallel loop. When the process shows dialog and gets the information. It returns and other threads keeps running.
However my team leader insist that there is a better way to do it which I couldn't figure out after doing hours of search :\
I tried a seperate thread in parallel for. It didn't worked.
I tried CWinThread (google say it is gui thread :\ which didn't helped)
I tired creating an exe and running it. That worked :)
int someCriticDialog()
{
#pragma omp critic (showCriticDlg)
{
CMyDialog ccc;
ccc.DoModal();
/* However the code below works
CreateProcess("someCriticDlg.exe", null, &hProcess);
WaitForSingeObject(hProcess, INFINITE);
*/
}
}
#pragma omp parallel
for (int i = 0; i < 5; i++)
someCriticDialog();
Let's say here is the problem:
void trouble_maker()
{
Sleep(10000);//application stops for 10 seconds
}
You can use PostMessage + PeekMessage + modal dialog to wait for it to finish through GUI window:
void PumpWaitingMessages()
{
MSG msg;
while (::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE))
if (!AfxGetThread()->PumpMessage())
return;
}
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_COMMAND(2000, OnDoSomething)
ON_COMMAND(IDCANCEL, OnCancel)
END_MESSAGE_MAP()
CMyDialog::CMyDialog(CWnd* par /*=NULL*/) : CDialog(IDD_DIALOG1, par)
{
working = false;
stop = false;
}
BOOL CMyDialog::OnInitDialog()
{
BOOL res = CDialog::OnInitDialog();
//call the function "OnDoSomething", but don't call it directly
PostMessage(WM_COMMAND, 2000, 0);
return res;
}
void CMyDialog::OnCancel()
{
if (working)
{
stop = true;
}
else
{
CDialog::OnCancel();
}
}
void CMyDialog::OnDoSomething()
{
HANDLE h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&trouble_maker, NULL, 0, NULL);
working = true;
for (;;)
{
if (WAIT_TIMEOUT != WaitForSingleObject(h, 100)) break;
PumpWaitingMessages();
//update progress bar or something...
if (stop)
{
//terminate if it's safe
//BOOL res = TerminateThread(h, 0);
//CloseHandle(h);
//CDialog::OnCancel();
//return;
}
}
working = false;
MessageBox("done");
}

Make new connections when blocked in a select() call

I have 2 threads:
Thread A:
It's the select() loop. Perform socket handling for reading operations, such as accepting new connections, receiving data.
while (1) {
FD_ZERO(&fdReadSet);
numActiveSockets = 0;
for (std::unordered_map<SOCKET, TcpSocket*>::iterator it = m_sock_table.begin(); it != m_sock_table.end(); it++)
{
numActiveSockets++;
FD_SET(it->first, &fdReadSet);
}
int ret;
bool hasListen = false;
if (( ret = select(numActiveSockets, &fdReadSet, NULL, NULL, NULL)) == SOCKET_ERROR) {
printf("Select Failed, Error code = %d\n", WSAGetLastError());
return -1;
}
for (std::unordered_map<SOCKET, TcpSocket*>::iterator it = m_sock_table.begin(); it != m_sock_table.end(); it++)
{
if (FD_ISSET(it->first, &fdReadSet))
{
if (it->first == TcpSocket::m_listen_sock)
{
if (!hasListen)
{
sockaddr_in sock_addr;
int sockLength = sizeof(sock_addr);
SOCKET sock = accept(it->first, (sockaddr *) &sock_addr, &sockLength);
TcpSocket * socket = new TcpSocket();
socket->m_sock = sock;
m_sock_table[sock] = socket;
it = m_sock_table.begin();
hasListen = true;
}
}
else
{
char * buffer = it->second->GetWriteBuffer();
int numRead = recv(it->first, buffer, SOCKET_BUFFER_SIZE, 0);
if (numRead == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err == WSAECONNRESET)
{
printf("Connection [%i]: RESET Received. Closing Socket\n", it->first);
closesocket(it->first);
it = socketVector.erase(it->first); // iterator invalidated after erase
}
else
{
printf("Recv Failed. Error code = %d\n", err);
return -1;
}
}
else if (numRead == 0)//connection close
{
printf("Connection [%i]: Graceful exit. Closing Socket\n", it->first);
closesocket(it->first);
it = socketVector.erase(it->first); // iterator invalidated after erase
}
else {
/* Process received data */
}
}
}
}
}
Thread B:
Allow the application to perform connect() to establish new connections. If a connect() is successful, it will the add the returned socket to m_sock_table.
I have a socket table called m_sock_table which holds all the sockets. I use this m_sock_table to initialize the fdReadSet to be used in select().
-----------Problem-----------------
If thread A is blocked by select(), and at the same time thread B establish a new connection through connect(), the application wouldn't be able to receive data from the new connection, because fdReadset has not been updated withed the new connected socket.
What would be a good way to solve this problem? Or the design is just wrong from the start?
You could use a signal that doesn't do anything other than interrupting the system call:
#include <signal.h>
void do_nothing() { }
struct sigaction sa;
sa.sa_handler = do_nothing;
sigemptyset(sa.sa_mask);
#ifdef SA_INTERRUPT
sa.sa_flags = SA_INTERRUPT;
#else
sa.sa_flags = 0;
#endif
sigaction(SIGUSR1, &sa, 0);
Then, in thread B, after starting a new connection, send the signal, after making sure thread A will handle it:
/* need only be done once, but needed in every thread other than A */
sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs, SIGUSR1)
pthread_sigmask(SIG_BLOCK, &sigs, 0);
/* each time we create a new connection */
kill(getpid, SIGUSR1);
With the above, select will return with an EINTR error -- so check for that and loop (adding the new connection to the set).

CreateThread doesn't work in my code

I wonder how to solve this problem.
I notice that CreateThread() doesn't work well in this code:
DWORD threadFunc1(LPVOID lParam)
{
int cur = (int)lParam
while(1)
{
//Job1...
//Reason
break;
}
Start(cur + 1);
Sleep(100);
}
void Start(int startNum)
{
....
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)threadFunc1, &startNum, 0, &dwThreadId);
...
}
void btnClicking()
{
Start(0);
}
In this code, there is a thread create by Start() and it calls Start() when the thread ends.
The second created thread does not work. I think the first thread disappeared and the second thread is destroyed.
What is the best way to solve this?
OS: Win 7 64bit Ultimate.
Tool: Visual Studio 2008.
It does not work because your code has bugs in it. The signature of your thread function is wrong, and you are passing the startNum value to the thread in the wrong way.
Try this instead:
DWORD WINAPI threadFunc1(LPVOID lParameter)
{
int cur = (int) lParameter;
while(1)
{
//Job1...
//Reason
break;
}
Start(cur + 1);
Sleep(100);
}
void Start(int startNum)
{
....
HANDLE hThread = CreateThread(NULL, NULL, &threadFunc1, (LPVOID) startNum, 0, &dwThreadId);
if (hThread != NULL)
{
// ... store it somewhere or close it, otherwise you are leaking it...
}
...
}
void btnClicking()
{
Start(0);
}

Resources