I need to create two threads that strictly alternates. Here is sample code what I use:
#include <Windows.h>
#include <iostream>
using std::cout;
using std::endl;
HANDLE g_hMutex1;
HANDLE g_hMutex2;
DWORD WINAPI ThreadFunc1(LPVOID lpParam);
DWORD WINAPI ThreadFunc2(LPVOID lpParam);
int main(void)
{
int nCalcNumber = 10;
DWORD dwThreadId;
HANDLE pThreadHandles[2];
g_hMutex1 = CreateMutex(NULL, FALSE, NULL);
g_hMutex1 = CreateMutex(NULL, FALSE, NULL);
pThreadHandles[0] = CreateThread(
NULL,
0,
ThreadFunc1,
static_cast<void*>(&nCalcNumber),
0,
&dwThreadId);
pThreadHandles[1] = CreateThread(
NULL,
0,
ThreadFunc2,
static_cast<void*>(&nCalcNumber),
0,
&dwThreadId);
WaitForMultipleObjects(2, pThreadHandles, TRUE, INFINITE);
CloseHandle(pThreadHandles[0]);
CloseHandle(pThreadHandles[1]);
CloseHandle(g_hMutex1);
CloseHandle(g_hMutex2);
return 0;
}
DWORD WINAPI ThreadFunc1(LPVOID lpParam)
{
int* nCalcNumber = static_cast<int*>(lpParam);
for (int i = 0; i < *nCalcNumber; i++)
{
WaitForSingleObject(g_hMutex1, INFINITE);
cout << "Func 1" << endl;
ReleaseMutex(g_hMutex1);
}
return 0;
}
DWORD WINAPI ThreadFunc2(LPVOID lpParam)
{
int* nCalcNumber = static_cast<int*>(lpParam);
for (int i = 0; i < *nCalcNumber; i++)
{
WaitForSingleObject(g_hMutex1, INFINITE);
cout << "Func 2" << endl;
ReleaseMutex(g_hMutex1);
}
return 0;
}
And a result, which I expect to receive:
Func 1
Func 2
Func 1
Func 2
Func 1
Func 2
...and so one
What should be added to get the desired result. Can I use for that the second mutex?
As noted in other answers, a semaphore is a much better choice than a mutex. But as a purely academic exercise (homework assignment?), you can do this with a mutex, too. (Emphasis: This is a purely academic exercise. A real program shouldn't use this technique.)
DWORD WINAPI ThreadFunc1(LPVOID lpParam)
{
int* nCalcNumber = static_cast<int*>(lpParam);
WaitForSingleObject(g_hMutex2, INFINITE);
for (int i = 0; i < *nCalcNumber; i++)
{
WaitForSingleObject(g_hMutex1, INFINITE);
ReleaseMutex(g_hMutex2);
cout << "Func 1" << endl;
ReleaseMutex(g_hMutex1);
WaitForSingleObject(g_hMutex2, INFINITE);
}
return 0;
}
DWORD WINAPI ThreadFunc2(LPVOID lpParam)
{
int* nCalcNumber = static_cast<int*>(lpParam);
WaitForSingleObject(g_hMutex2, INFINITE);
for (int i = 0; i < *nCalcNumber; i++)
{
WaitForSingleObject(g_hMutex1, INFINITE);
ReleaseMutex(g_hMutex2);
cout << "Func 2" << endl;
ReleaseMutex(g_hMutex1);
WaitForSingleObject(g_hMutex2, INFINITE);
}
return 0;
}
Mutex 1 is the "I have it" mutex, and Mutex 2 is the "I want it next" mutex.
If you can use semaphore: You can use semaphore instead of mutex, it's easy to use same as mutex.
This code works fine:
#include <windows.h>
#include <iostream>
using std::cout;
using std::endl;
PHANDLE sem1;
PHANDLE sem2;
DWORD WINAPI ThreadFunc1(LPVOID lpParam);
DWORD WINAPI ThreadFunc2(LPVOID lpParam);
int main(void)
{
int nCalcNumber = 10;
DWORD dwThreadId;
HANDLE pThreadHandles[2];
sem1 = (PHANDLE) CreateSemaphore(NULL, 1, 1, NULL);
sem2 = (PHANDLE) CreateSemaphore(NULL, 0, 1, NULL);
pThreadHandles[0] = CreateThread(
NULL,
0,
ThreadFunc1,
static_cast<void*> (&nCalcNumber),
0,
&dwThreadId);
pThreadHandles[1] = CreateThread(
NULL,
0,
ThreadFunc2,
static_cast<void*> (&nCalcNumber),
0,
&dwThreadId);
WaitForMultipleObjects(2, pThreadHandles, TRUE, INFINITE);
CloseHandle(pThreadHandles[0]);
CloseHandle(pThreadHandles[1]);
CloseHandle(sem1);
CloseHandle(sem2);
return 0;
}
DWORD WINAPI ThreadFunc1(LPVOID lpParam)
{
int* nCalcNumber = static_cast<int*> (lpParam);
for (int i = 0; i < *nCalcNumber; i++)
{
WaitForSingleObject(sem1, INFINITE);
cout << "Func 1" << endl;
ReleaseSemaphore(sem2, 1 ,NULL);
}
return 0;
}
DWORD WINAPI ThreadFunc2(LPVOID lpParam)
{
int* nCalcNumber = static_cast<int*> (lpParam);
for (int i = 0; i < *nCalcNumber; i++)
{
WaitForSingleObject(sem2, INFINITE);
cout << "Func 2" << endl;
ReleaseSemaphore(sem1, 1 ,NULL);
}
return 0;
}
You're assuming that OS actually supports this. Windows doesn't. It has no guarantee about the scheduling, other then no starvation.
So what you need to do is to set a flag variable, so that each thread will change it to allow the other thread to run. For example, if it's true - run, if it's false - release the mutex and sleep for awhile, and the other thread - exactly the opposite. Sleep is important here to avoid starvation and deadlock. I think it can be Sleep(0) (check if it means "yield" in Windows, I'm not sure).
Of course, the checks should be done when the mutex is taken, and at the end of the run each thread will change the variable to the opposite - to allow the other thread to run and block itself until the other thread does run and changes it back.
It can be easily changed to more than 2 threads by making the variable a counter modulo the number of threads, and each thread increasing the value at the end of the run, and checking the value modulo to be the thread's number in order of the execution at the beginning.
edit
volatile bool flag = false;
DWORD WINAPI ThreadFunc1(LPVOID lpParam)
{
int* nCalcNumber = static_cast<int*>(lpParam);
for (int i = 0; i < *nCalcNumber; /*no-op*/;)
{
WaitForSingleObject(g_hMutex1, INFINITE);
if (flag) {Sleep(0); continue;}
cout << "Func 1" << endl;
flag = true;
i++;
ReleaseMutex(g_hMutex1);
}
return 0;
}
DWORD WINAPI ThreadFunc2(LPVOID lpParam)
{
int* nCalcNumber = static_cast<int*>(lpParam);
for (int i = 0; i < *nCalcNumber; /*no-op*/;)
{
WaitForSingleObject(g_hMutex1, INFINITE);
if (!flag) {Sleep(0); continue;}
cout << "Func 2" << endl;
flag = false;
i++;
ReleaseMutex(g_hMutex1);
}
return 0;
}
Related
I wanted to calculate the time between creating a thread and taking control by it, then compare this time for normal and suspended threads. But the results are quite chaotic.
So, my question is: Does it really makes sense? I think that instant resuming doesn't have a visible effect on the result.
#include <iostream>
#include <windows.h>
using namespace std;
DWORDLONG freq;
DWORD WINAPI startThread(LPVOID lpParam) {
DWORDLONG c_beg = *((DWORDLONG*)lpParam);
DWORDLONG c_end;
QueryPerformanceCounter((LARGE_INTEGER*)&c_end);
cout << (double(c_end - c_beg)) / (freq) << endl;
return 0;
}
int main()
{
DWORDLONG c_beg;
HANDLE iThread, sThread;
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
cout << "instant" << endl;
for (int i = 0; i < 10; i++) {
QueryPerformanceCounter((LARGE_INTEGER*)&c_beg);
iThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)startThread, (LPVOID*)&c_beg, 0, NULL);
WaitForSingleObject(iThread, INFINITE);
}
cout << "suspended" << endl;
for (int i = 0; i < 10; i++) {
QueryPerformanceCounter((LARGE_INTEGER*)&c_beg);
sThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)startThread, (LPVOID*)&c_beg, CREATE_SUSPENDED, NULL);
ResumeThread(sThread);
WaitForSingleObject(sThread, INFINITE);
}
CloseHandle(iThread);
CloseHandle(sThread);
return 0;
}
Hello I want to sync two threads one incrementing a variable and other decrementing it.
The result that I want looks like:
Thread #0 j = 1
Thread #1 j = 0
Thread #0 j = 1
Thread #1 j = 0
And so on.. but my code sometimes works like that in some cases it print really weird values. I supose that I have some undefined behavior in somewhere but I can't figured out what is really happen.
My code consist in a HANDLE ghMutex that containg the handler of my mutex:
My main function:
int main(void)
{
HANDLE aThread[THREADCOUNT];
ghMutex = CreateMutex(NULL, FALSE, NULL);
aThread[0] = (HANDLE)_beginthreadex(NULL, 0, &inc, NULL, CREATE_SUSPENDED, 0);
aThread[1] = (HANDLE)_beginthreadex(NULL, 0, &dec, NULL, CREATE_SUSPENDED, 0);
ResumeThread(aThread[0]);
ResumeThread(aThread[1]);
WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
printf("j = %d\n", j);
for (int i = 0; i < THREADCOUNT; i++)
CloseHandle(aThread[i]);
CloseHandle(ghMutex);
return 0;
}
Inc function:
unsigned int __stdcall inc(LPVOID)
{
for (volatile int i = 0; i < MAX; ++i)
{
WaitForSingleObject(
ghMutex, // handle to mutex
INFINITE); // no time-out interval
j++;
printf("Thread %d j = %d\n", GetCurrentThreadId(), j);
ReleaseMutex(ghMutex);
}
_endthread();
return TRUE;
}
Dec function:
unsigned int __stdcall dec(void*)
{
for (volatile int i = 0; i < MAX; ++i)
{
WaitForSingleObject(
ghMutex, // handle to mutex
INFINITE); // no time-out interval
j--;
printf("Thread %d j = %d\n", GetCurrentThreadId(), j);
ReleaseMutex(ghMutex);
}
_endthread();
return TRUE;
}
I need a win api solution in std c++98.
A mutex is not the right tool to synchronize two threads, it is there to protect a resource. You do have a resource j which is protected by your mutex, however the sequence of which thread gets the lock is undefined, so you can have the case where dec gets called several times before inc has the chance to run.
If you want to synchronize the order of the threads you will have to use another synchronization primitive, for example a semaphore. You could, for example, increment the semaphore in inc and decrement it in dec. This would be the classic producer - consumer relationship where the producer will be stalled when the semaphore reaches its maximum value and the consumer will wait for items to consume.
Sorry, no WinAPI C++98 solution from me because that would be silly, but I hope I pointed you to the right direction.
windows mutex object guarantees exclusive ownership, but does not care about the ownership order. so that the same thread can capture several times in a row while others will wait.
for your task you need signal to another thread, when your task is done, and then wait for signal from another thread. for this task can be used event pair for example. thread (i) signal event (1-i) and wait on event (i). for optimize instead 2 calls -
SetEvent(e[1-i]); WaitForSingleObject(e[i], INFINITE);
we can use single call SignalObjectAndWait
SignalObjectAndWait(e[1-i], e[i], INFINITE, FALSE)
of course start and end of loop require special care. for inc
HANDLE hObjectToSignal = _hEvent[1], hObjectToWaitOn = _hEvent[0];
for (;;)
{
_shared_value++;
if (!--n)
{
SetEvent(hObjectToSignal);
break;
}
SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, INFINITE, FALSE);
}
and for dec
HANDLE hObjectToSignal = _hEvent[0], hObjectToWaitOn = _hEvent[1];
WaitForSingleObject(hObjectToWaitOn, INFINITE);
for (;;)
{
--_shared_value;
if (!--n)
{
break;
}
SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, INFINITE, FALSE);
}
if write full test, with error checking
struct Task
{
HANDLE _hEvent[4];
ULONG _n;
LONG _iTasks;
LONG _shared_value;
Task()
{
RtlZeroMemory(this, sizeof(*this));
}
~Task()
{
ULONG n = RTL_NUMBER_OF(_hEvent);
do
{
if (HANDLE hEvent = _hEvent[--n]) CloseHandle(hEvent);
} while (n);
}
ULONG WaitTaskEnd()
{
return WaitForSingleObject(_hEvent[2], INFINITE);
}
ULONG WaitTaskReady()
{
return WaitForSingleObject(_hEvent[3], INFINITE);
}
void SetTaskReady()
{
SetEvent(_hEvent[3]);
}
void End()
{
if (!InterlockedDecrement(&_iTasks)) SetEvent(_hEvent[2]);
}
void Begin()
{
InterlockedIncrementNoFence(&_iTasks);
}
static ULONG WINAPI IncThread(PVOID p)
{
return reinterpret_cast<Task*>(p)->Inc(), 0;
}
void Inc()
{
if (WaitTaskReady() == WAIT_OBJECT_0)
{
if (ULONG n = _n)
{
HANDLE hObjectToSignal = _hEvent[1], hObjectToWaitOn = _hEvent[0];
for (;;)
{
if (_shared_value) __debugbreak();
if (n < 17) DbgPrint("Inc(%u)\n", n);
_shared_value++;
if (!--n)
{
SetEvent(hObjectToSignal);
break;
}
if (SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, INFINITE, FALSE) != WAIT_OBJECT_0)
{
break;
}
}
}
}
End();
}
static ULONG WINAPI DecThread(PVOID p)
{
return reinterpret_cast<Task*>(p)->Dec(), 0;
}
void Dec()
{
if (WaitTaskReady() == WAIT_OBJECT_0)
{
if (ULONG n = _n)
{
HANDLE hObjectToSignal = _hEvent[0], hObjectToWaitOn = _hEvent[1];
if (WaitForSingleObject(hObjectToWaitOn, INFINITE) == WAIT_OBJECT_0)
{
for (;;)
{
--_shared_value;
if (_shared_value) __debugbreak();
if (n < 17) DbgPrint("Dec(%u)\n", n);
if (!--n)
{
break;
}
if (SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, INFINITE, FALSE) != WAIT_OBJECT_0)
{
break;
}
}
}
}
}
End();
}
ULONG Create()
{
ULONG n = RTL_NUMBER_OF(_hEvent);
do
{
if (HANDLE hEvent = CreateEventW(0, n > 2, 0, 0)) _hEvent[--n] = hEvent;
else return GetLastError();
} while (n);
return NOERROR;
}
ULONG Start()
{
static PTHREAD_START_ROUTINE aa[] = { IncThread, DecThread };
ULONG n = RTL_NUMBER_OF(aa);
do
{
Begin();
if (HANDLE hThread = CreateThread(0, 0, aa[--n], this, 0, 0))
{
CloseHandle(hThread);
}
else
{
n = GetLastError();
End();
return n;
}
} while (n);
return NOERROR;
}
ULONG Start(ULONG n)
{
_iTasks = 1;
ULONG dwError = Start();
_n = dwError ? 0 : n;
SetTaskReady();
End();
return dwError;
}
};
void TaskTest(ULONG n)
{
Task task;
if (task.Create() == NOERROR)
{
task.Start(n);
task.WaitTaskEnd();
}
}
note, that no any sense declare local variable (which will be accessed only from single thread and not accessed by any interrupts, etc) as volatile
also when we write code, like:
// thread #1
write_shared_data();
SetEvent(hEvent);
// thread #2
WaitForSingleObject(hEvent, INFINITE);
read_shared_data();
inside SetEvent(hEvent); was atomic write to event state with release semantic (really stronger of course) and inside wait for event function - atomic read it state with more than acquire semantic. as result all what thread #1 write to memory before SetEvent - will be visible to thread #2 after Wait for event (if wait finished as result of call Set from thread #1)
I have written a function which It is doing the Fibonacci calculation. I wanted to start and execute it with CreateThread as a thread. Finally, I want to save the result of the thread (the Fibonacci) and show it in the console. What is the problem with my code? It doesn't work properly. It starts the thread, but I don't know how should I store the result of the thread and show it.
#include <Windows.h>
#include <iostream>
DWORD WINAPI Fibonacci(LPVOID arg_repeat) {
DWORD dwValue = *(int*)arg_repeat;
if (dwValue < 3)
return 1;
return Fibonacci((int*)dwValue - 1) + Fibonacci((int*)dwValue - 2);
}
auto main(int argc, const char* argv[]) -> decltype(0) {
DWORD dwFibonacciValue;
std::cout << "Fibonacci Value: ";
std::cin >> dwFibonacciValue;
DWORD dwThreadId;
HANDLE hThreading = CreateThread(NULL, 0, Fibonacci, &dwFibonacciValue, NULL, &dwThreadId);
WaitForSingleObject(hThreading, INFINITE);
std::cout << "Fibonacci Result: " << dwResult << std::endl;
CloseHandle(hThreading);
return 0;
}
Your code is wrong beause (int*)dwValue - 1 is not a valid pointer.
You should separate the thread function from the fibonacci function. There will be much less dubious and wrong casts and code will be much clearer:
#include <Windows.h>
#include <iostream>
// Clean and easy to read fibonacci function without fancy casts
DWORD Fibonacci(DWORD dwValue) {
if (dwValue < 3)
return 1;
return Fibonacci(dwValue - 1) + Fibonacci(dwValue - 2);
}
// Thread function
DWORD WINAPI Thread(LPVOID arg_repeat) {
return Fibonacci(*(DWORD*)arg_repeat); // the only cast int the whole code
}
int main(int argc, const char* argv[]) -> decltype(0) {
// it's 'int main', not 'auto main'
DWORD dwFibonacciValue;
std::cout << "Fibonacci Value: ";
std::cin >> dwFibonacciValue;
DWORD dwThreadId;
HANDLE hThreading = CreateThread(NULL, 0, Thread, &dwFibonacciValue, 0, &dwThreadId);
WaitForSingleObject(hThreading, INFINITE);
// get return value of the thread (your actual question)
DWORD dwResult;
GetExitCodeThread(hThreading, &dwResult);
std::cout << "Fibonacci Result: " << dwResult << std::endl;
CloseHandle(hThreading);
return 0;
}
There is no error check whatsoever in this code for clarity.
Other detail:
CreateThread(NULL, 0, Thread, &dwFibonacciValue, NULL, &dwThreadId);
// ^ you should provide a DWORD
// here and not a pointer
should be
CreateThread(NULL, 0, Thread, &dwFibonacciValue, 0, &dwThreadId);
I modified the "Using Condition Variables" example in MSDN. I created several threads, which have their own producer/consumer separately.
But the program will often hang when attached to debugger. It always hangs at SleepConditionVariableCS. When I break all and continue in debugger, the program will continue to run. I found that WakeAllConditionVariable didn't wake up some thread calls SleepConditionVariableCS, for the Ptr in PExecutingTask->BufferNotFull or PExecutingTask->BufferNotEmpty was already 0x00000000(I thought that means the condition variable is wakened).
When not attached to debugger, the program will not hang.
Has anyone encountered this problem before? How to solve it?
Here is the code:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#define BUFFER_SIZE 100
DWORD WINAPI ProducerThreadProc (PVOID p);
DWORD WINAPI ConsumerThreadProc (PVOID p);
class ExecutingTask
{
public:
void Initialize()
{
InitializeConditionVariable (&BufferNotEmpty);
InitializeConditionVariable (&BufferNotFull);
InitializeCriticalSection (&BufferLock);
QueueSize = 0;
StopRequested = FALSE;
hProducer = CreateThread(NULL, 0, ProducerThreadProc, (PVOID)this, 0, NULL);
for (int i = 0; i < 20; i++)
{
PhConsumers[i] = CreateThread (NULL, 0, ConsumerThreadProc, (PVOID)this, 0, NULL);
}
}
void Stop()
{
EnterCriticalSection (&BufferLock);
StopRequested = TRUE;
LeaveCriticalSection (&BufferLock);
WakeAllConditionVariable (&BufferNotFull);
WakeAllConditionVariable (&BufferNotEmpty);
WaitForSingleObject(hProducer, INFINITE);
WaitForMultipleObjects(20, (HANDLE *)&PhConsumers, true, INFINITE);
CloseHandle(hProducer);
for (unsigned int i = 0; i < 20; i++)
{
CloseHandle(PhConsumers[i]);
}
}
public:
ULONG QueueSize;
CONDITION_VARIABLE BufferNotEmpty;
CONDITION_VARIABLE BufferNotFull;
CRITICAL_SECTION BufferLock;
BOOL StopRequested;
HANDLE PhConsumers[20];
HANDLE hProducer;
};
DWORD WINAPI ProducerThreadProc (PVOID p)
{
ExecutingTask* PExecutingTask = (ExecutingTask*)p;
while (true)
{
EnterCriticalSection (&PExecutingTask->BufferLock);
while (PExecutingTask->QueueSize >= BUFFER_SIZE && PExecutingTask->StopRequested == FALSE)
{
// Buffer is full - sleep so consumers can get items.
SleepConditionVariableCS (&PExecutingTask->BufferNotFull, &PExecutingTask->BufferLock, INFINITE);
}
if (PExecutingTask->StopRequested == TRUE)
{
LeaveCriticalSection (&PExecutingTask->BufferLock);
break;
}
// Produce an item.
PExecutingTask->QueueSize++;
LeaveCriticalSection (&PExecutingTask->BufferLock);
WakeConditionVariable (&PExecutingTask->BufferNotEmpty);
}
return 0;
}
DWORD WINAPI ConsumerThreadProc (PVOID p)
{
ExecutingTask* PExecutingTask = (ExecutingTask*)p;
while (true)
{
EnterCriticalSection (&PExecutingTask->BufferLock);
while (PExecutingTask->QueueSize == 0 && PExecutingTask->StopRequested == FALSE)
{
// Buffer is empty - sleep so producers can create items.
SleepConditionVariableCS (&PExecutingTask->BufferNotEmpty, &PExecutingTask->BufferLock, INFINITE);
}
if (PExecutingTask->StopRequested == TRUE)
{
LeaveCriticalSection (&PExecutingTask->BufferLock);
break;
}
// Consume an item.
PExecutingTask->QueueSize--;
LeaveCriticalSection (&PExecutingTask->BufferLock);
WakeConditionVariable (&PExecutingTask->BufferNotFull);
}
return 0;
}
DWORD WINAPI ThreadProc (PVOID p)
{
ExecutingTask task;
task.Initialize();
Sleep(1000);
task.Stop();
printf ("%u exit\n", &task);
return 0;
};
int main ( void )
{
HANDLE hTaskThreads[50];
for (int i = 0; i < 50; i++)
{
hTaskThreads[i] = CreateThread (NULL, 0, ThreadProc, NULL, 0, NULL);
}
WaitForMultipleObjects(50, hTaskThreads, true, INFINITE);
for (int i = 0; i < 50; i++)
{
CloseHandle(hTaskThreads[i]);
}
}
I am trying to create files in a pen drive. If the pen drive is not present, threads should suspend. When it is inserted it should resume. Here is the code I tried but it's not working properly. Can any one help me?
#include "stdafx.h"
#include <Windows.h>
#include <Strsafe.h>
#include <WinBase.h>
LPCTSTR Disk=L"E:\";
LPTSTR drive_Name=L"E:\\demo";
CRITICAL_SECTION section;
#define BUFFER_SIZE 1024
#define count 10
HANDLE Write_Handle[10],Open_Handle[10],read_Handle[10] ;
DWORD WINAPI check_Thread(LPVOID lpParameter)
{
int *nThreadNo = (int*)lpParameter;
while(1)
{
if(GetDiskFreeSpaceExW(Disk,NULL,NULL,NULL))
{
ResumeThread(Write_Handle[*nThreadNo]);
ResumeThread(read_Handle[*nThreadNo]);
}
else
{
SuspendThread(Write_Handle[*nThreadNo]);
SuspendThread(read_Handle[*nThreadNo]);
}
}
}
DWORD WINAPI Write_Thread(LPVOID lpParameter)
{
DWORD g_tid = GetCurrentThreadId();
_tprintf(_T(" write thread id %d\n"),g_tid);
LPCWSTR filename=(LPCWSTR)lpParameter;
HANDLE ofile;
EnterCriticalSection(§ion);
ofile=CreateFileW(filename,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,NULL, NULL);
int d;
d=GetLastError();
if(ERROR_SUCCESS!=GetLastError())
{
_tprintf(_T("error values in open thread %d \n"),GetLastError());
_tprintf(_T("filename %s \n"),filename);
}
const int filesizeinKB = 1024;
BOOL bError;
DWORD dwBytesWritten=0;
WCHAR ReadBuffer[BUFFER_SIZE] = {0};
int i;
for(i = 0; i <= BUFFER_SIZE; i++)
{
ReadBuffer[i] = (char)(i%26 + 'a');
}
for (i = 0; i <= filesizeinKB; i++)
{
SetLastError(0);
bError= WriteFile(ofile, ReadBuffer-1, BUFFER_SIZE,&dwBytesWritten, NULL);
bError=GetLastError();
if (ERROR_SUCCESS!=GetLastError())
{ _tprintf(_T("error value in write %d\n"),GetLastError());
_tprintf(_T(" Write Error...\n"));
return 1;
}
}
SetLastError(0);
CloseHandle(ofile);
_tprintf(_T("write close error values %d\n"),GetLastError());
LeaveCriticalSection(§ion);
return 1;
}
DWORD WINAPI Read_Thread(LPVOID lpParameter)
{
HANDLE ofile;
DWORD g_tid = GetCurrentThreadId();
_tprintf(_T(" write thread id %d\n"),g_tid);
LPCWSTR filename=(LPCWSTR)lpParameter;
EnterCriticalSection(§ion);
ofile=CreateFileW(filename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_ALWAYS,NULL, NULL);
int d;
d=GetLastError();
if(ERROR_SUCCESS!=GetLastError())
{
_tprintf(_T("error values in open thread %d \n"),GetLastError());
_tprintf(_T("filename %s \n"),filename);
}
DWORD dwBytesRead=0;
WCHAR ReadBuffer[BUFFER_SIZE] = {0};
_tprintf(_T(" read thread \n"));
SetLastError(0);
int err;
ReadFile(ofile, ReadBuffer, (BUFFER_SIZE-1), &dwBytesRead, NULL);
err=GetLastError();
_tprintf(_T("read error values %d \n"),GetLastError());
if(ERROR_SUCCESS!=GetLastError())
{
_tprintf(L"reading failed \n");
return 0;
}
SetLastError(0);
CloseHandle(ofile);
err=GetLastError();
_tprintf(_T("close error values %d\n"),GetLastError());
LeaveCriticalSection(§ion);
return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
unsigned int myCounter = 0;
DWORD WritethreadID,OpenThreadID,ReadthreadID;
HANDLE check_Handle;
DWORD exThread;
TCHAR filename[100];
HANDLE hfile;
INT bsize=100;
int i=0;
InitializeCriticalSection (§ion);
CreateDirectory(drive_Name,NULL);
for(i=0;i<5;i++)
{
SetLastError(0);
StringCchPrintf(filename,bsize, TEXT("%s\\file_%d.txt"),drive_Name,i );
hfile=CreateFileW(filename,GENERIC_WRITE|GENERIC_READ,NULL,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if (hfile == INVALID_HANDLE_VALUE)
{
_tprintf(_T("invalid handle \n" ));
}
_tprintf(_T("file created %s\n"),filename);
CloseHandle(hfile);
Write_Handle[i] =CreateThread(0, 0, Write_Thread, filename, CREATE_SUSPENDED, &WritethreadID);
SetThreadPriority(Write_Handle[i],2);
_tprintf(_T("write thread id is %d\n"),WritethreadID);
read_Handle[i]=CreateThread(0, 0, Read_Thread, filename, CREATE_SUSPENDED, &ReadthreadID);
SetThreadPriority(read_Handle[i],1);
_tprintf(_T("read thread id is %d\n "),ReadthreadID);
check_Handle =CreateThread(0, 0, check_Thread,(void*)&i ,0,&OpenThreadID);
}
for (i=0; i<count; ++i)
{
WaitForSingleObject(Write_Handle[i],INFINITE);
if ( !GetExitCodeThread(Write_Handle, &exThread) )
{
_tprintf(_T("close thread %08X\n"),GetLastError());
}
SetLastError(0);
CloseHandle(Write_Handle[i]);
_tprintf(_T("close thread %08X\n"),GetLastError());
WaitForSingleObject(read_Handle[i],INFINITE);
if ( !GetExitCodeThread(read_Handle, &exThread) )
{
_tprintf(_T("GetExitCodeThread %08X\n"),GetLastError());
}
SetLastError(0);
CloseHandle(read_Handle[i]);
_tprintf(_T("GetExitCodeThread %08X\n"),GetLastError());
CloseHandle(check_Thread);
}
DeleteCriticalSection(§ion);
return 1;
}
If you have open file handles to a USB drive when that drive is removed, those file handles will become invalid. Reinserting the USB drive will not reconstitute those handles in such a way that you can continue after resuming a thread.
You will need to:
detect when the device is removed, and close those now-broken handles
when the device is inserted, open the files again and continue whatever you were doing
Your error handlers are returning without calling LeaveCriticalSection, leaving the CS locked and blocking the other threads indefinitely. From the EnterCriticalSection docs:
If a thread terminates while it has ownership of a critical section,
the state of the critical section is undefined.
Those cases also leave the file handles open.