As far as I can see, a pointer to structure can be used. But I am wondering, is there any more efficient or elegant way to do that? At least when a structure is being used, it is not easy to see what are the parameters used by the function.
Thanks for any insightful answer.
Here's a small example, that uses WIN32 API:
#include <windows.h>
#include <stdio.h>
struct PARAMS
{
int i;
char* msg;
};
DWORD WINAPI myThread(void* parameter)
{
PARAMS* params = (PARAMS*)parameter;
printf("Received parameters: i = %d, msg = '%s'\n", params->i, params->msg);
return 0;
}
int main(int argc, char* argv[])
{
char msg[] = "Hi there.";
PARAMS params;
params.i = 1;
params.msg = msg;
HANDLE threadHandle = CreateThread(NULL, 0, myThread, ¶ms, 0, NULL);
WaitForSingleObject(threadHandle, INFINITE);
return 0;
}
You say, that "it is not easy to see what are the parameters used by the function". Well it depends on situation. If you don't consider it "elegant" enough, you should leave some helpful comment there at least... if you are using good naming and trying to write code, that is self-documenting, then using of structure will be just fine.
Here's an example of wrapping CreateThread so that programmer that uses your code doesn't have to know that you are using some structure:
#include <windows.h>
#include <stdio.h>
class MyWrapper
{
private:
struct PARAMS
{
int i;
char* msg;
};
static DWORD WINAPI myThread(void* parameter)
{
PARAMS* params = (PARAMS*)parameter;
printf("Received parameters: i = %d, msg = '%s'\n", params->i, params->msg);
delete params;
return 0;
}
public:
HANDLE createThread(int i, char* msg)
{
PARAMS* params = new PARAMS;
params->i = i;
params->msg = msg;
return CreateThread(NULL, 0, MyWrapper::myThread, params, 0, NULL);
}
};
int main(int argc, char* argv[])
{
MyWrapper mw;
char msg[] = "Hi there.";
HANDLE threadHandle = mw.createThread(1, msg);
WaitForSingleObject(threadHandle, INFINITE);
return 0;
}
Here is a small example if you want to pass a single parameter to a thread function in Win32 API
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
DWORD WINAPI funHello(void *x)
{
int c = (int*)x;
printf("\n Thread No: %d\n",c);
// Do some work , call some function, etc.
return 0;
}
int main()
{
HANDLE myhandle;
DWORD threadId;
int c = 1;
myhandle = CreateThread(NULL, 0, funHello, (void *)c, 0, &threadId);
if (myhandle == NULL)
{
printf("Create Thread Failed. Error no: %d\n", GetLastError);
}
WaitForSingleObject(myhandle, INFINITE);
printf("\n Main Hello...\n");
CloseHandle(myhandle);
return 0;
}
Related
I have an array of objects and want each one to call a member function in a separate thread (so they run concurrently). I'm using _beginthreadex and can get it to work fine for a standard function but can't figure out the syntax to pass the member function to the _beginthreadex call. Here's an example of what I'm doing (the block of code after the second comment does not compile):
#include <Windows.h>
#include <process.h>
#include <stdio.h>
unsigned __stdcall mythread(void* data) {
printf("\nThread %d", GetCurrentThreadId());
return 0;
}
class myClass {
public:
unsigned __stdcall myClass::myThread(void* data);
};
unsigned __stdcall myClass::myThread(void* data) {
printf("\nThread %d", GetCurrentThreadId());
return(0);
}
int main(int argc, char* argv[]) {
int i, numThreads = 5;
// this works
HANDLE *myHandle = new HANDLE[numThreads];
for(i=0;i<numThreads;i++) myHandle[i] = (HANDLE)_beginthreadex(0, 0, &mythread, 0, 0, 0);
WaitForMultipleObjects(numThreads, myHandle, true, INFINITE);
for(i=0;i<numThreads;i++) CloseHandle(myHandle[i]);
getchar();
delete myHandle;
// this does not compile - not sure of syntax to call myObject[i].myThread in _beginthreadex
HANDLE *myHandle2 = new HANDLE[numThreads];
myClass *myObject = new myClass[numThreads];
for(i=0;i<numThreads;i++) myHandle2[i] = (HANDLE)_beginthreadex(0, 0, &myObject[i].myThread, 0, 0, 0);
WaitForMultipleObjects(numThreads, myHandle2, true, INFINITE);
for(i=0;i<numThreads;i++) CloseHandle(myHandle2[i]);
getchar();
delete myObject;
delete myHandle2;
return 0;
}
Thanks in advance for any help!
rgames
You cannot get address of member fuinction using
&myObject[i].myThread
correct way is like this
&myClass::myThread
In C++ functions and member functions have different signature like
/* pointer for this function would have type void(*)(int, float) */
void foo(int, float) { /* ... */ }
class A {
public:
/* pointer for this function would have type void(A::*)(int, float) */
void foo(int, float) { /* ... */ }
};
they are have different type even they both return void and take int and float.
As you can see in msdn the _beginthread function takes function as
unsigned (__stdcall *)( void * )
but you are trying to pass
unsigned (__stdcall myClass::*)( void* )
So to correct your code you can do:
Method 1: you need to write another function, something like
unsigned __stdcall mymemberthread(void* data) {
if (data != NULL) {
myClass* m = (myClass*)data;
m->myThread(m + 1);
}
return 0;
}
And create thread like
(HANDLE)_beginthreadex(0, 0, &mymemberthread, &myObject[i], 0, 0);
Method 2: make function myClass::myThread static
class myClass {
public:
static unsigned __stdcall myThread(void* data);
};
unsigned __stdcall myClass::myThread(void* data) {
printf("\nThread %d", GetCurrentThreadId());
if (data != NULL) {
myClass* m = (myClass*)data;
m->myThread(m + 1);
}
return(0);
}
...
(HANDLE)_beginthreadex(0, 0, &myClass::myThread, &myObject[i], 0, 0);
Method 3: if this is acceptabe use STL and std::thread, this will make you code more generic.
Like my title says, I'm trying to modify the CreateThread function. I want it to report the sequence number of the thread using the loop.
I'm fairly new to programming in C++ and am unsure which parameter needs to be altered. I suspect it may be the 'lpParameter' but after looking on microsofts website (https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453%28v=vs.85%29.aspx) I still do not understand how the parameters work.
So far I have:
int int_tmain(int argc, _TCHAR* argv[])
{
HANDLE hThread[numThreads];
int tNum[10];
for (int i = 0; i < numThreads; i++)
{
tNum[i] = i;
hThread[i] =
CreateThread(NULL, 0, helloFun, NULL, 0, NULL);
} WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE);
return 0;
}
Which produces a blank thread.
EDIT:
Sorry for the confusion guys. I have declared the thread routine:
const int numThreads = 4;
DWORD WINAPI helloFun(LPVOID pArg)
{
printf("Hello Thread \n");
return 0;
}
It's not clear what you are trying to do, but it is clear that you are calling WaitForMultipleObjects in the wrong place.
You are trying to wait for numThreads after only creating one thread. The rest of the hThread array is still uninitialized, and passing wild handles to WaitForMultipleObjects is a terrible idea.
Move the wait call outside the loop.
Your thread routine must be declared
DWORD name (LPVOID whatever)
Whatever is passed as lpParameter is passed to the thread. In this case, cast integer to pointer and back.
As you mentioned, if you want to pass a parameter to the thread, then you use the lpParameter. It expects a pointer, so you could pass, for instance, &i, although that's not exactly a good idea. You could create a pointer to int, and pass it, and then delete after WaitForMultipleObjectsreturns.
As Ben said, you are calling WaitForMultipleObjects in the wrong place.
Something like this should work:
int int_tmain(int argc, _TCHAR* argv[])
{
HANDLE hThread[numThreads];
int tNum[10];
int *parameters[numThreads];
for (int i = 0; i < numThreads; i++)
{
tNum[i] = i;
parameters[i] = new int(i);
hThread[i] = CreateThread(NULL, 0, helloFun, (void *)parameters[i], 0, NULL);
}
WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE);
for (int i = 0; i < numThreads; i++)
delete parameters[i];
return 0;
}
You will have to cast the lpParameter to int in your helloFun.
Try something more like this:
const int maxThreads = 4;
DWORD WINAPI helloFun(LPVOID pArg)
{
int num = * (int*) pArg;
printf("Hello from Thread %d\n", num);
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hThread[maxThreads];
int tNum[maxThreads];
int numThreads = 0;
for (int i = 0; i < maxThreads; i++)
{
tNum[numThreads] = i+1;
hThread[numThreads] = CreateThread(NULL, 0, &helloFun, &tNum[numThreads], 0, NULL);
if (hThread[numThreads] == NULL)
{
printf("Unable to create a thread! Error: %u\n", GetLastError());
break;
}
++numThreads;
}
if (numThreads > 0)
{
WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE);
for (int i = 0; i < numThreads; i++)
CloseHandle(hThread[i]);
}
return 0;
}
#include <stdio.h>
#include <process.h>
#include <wtypes.h>
typedef unsigned int (__stdcall * THREAD_FUN_TYPE)(void *);
int ThreadIp(void* param)
{
while(true)
{
printf("I'm runing!\n");
}
return 0;
}
int main()
{
int iThreadNum=100;
HANDLE* phThreads = new HANDLE[iThreadNum];
for (int i=0;i<iThreadNum;++i)
{
phThreads[i]=(HANDLE*)_beginthreadex(NULL, 0, (THREAD_FUN_TYPE)ThreadIp,NULL, NULL, NULL);
}
int nIndex = ::WaitForMultipleObjects(iThreadNum,phThreads,1,INFINITE);
printf("End!\n");
return 0;
}
I want the program will halt at WaitForMultipleObjects until all thread are end(Not until all thread are created successfully).But the program will not halt at WaitForMultipleObjects,while all threads are still running. So I try to use SetEvent,but still the same problem:
int iThreadNum=100;
HANDLE* phThreads = new HANDLE[iThreadNum];
for (int i=0;i<iThreadNum;++i)
{
phThreads[i]=CreateEvent(NULL, FALSE, FALSE,NULL);
ResetEvent(phThreads[i]);
}
int nIndex = ::WaitForMultipleObjects(iThreadNum,phThreads,1,INFINITE);
You should wait on the thread handles, not the unrelated events:
Try something like this:
int iThreadNum=100;
HANDLE* phThreads = new HANDLE[iThreadNum];
for (int i=0;i<iThreadNum;++i)
{
m_iCurThreadNum=i;
phThreads[i] = _beginthreadex(...);
}
int nIndex = ::WaitForMultipleObjects(iThreadNum,phThreads,1,INFINITE);
Does it work if you have fewer threads? The manual says you need to do extra work if you have more than MAXIMUM_WAIT_OBJECTS, specifically
nCount [in] The number of object handles in the array pointed to by
lpHandles. The maximum number of object handles is
MAXIMUM_WAIT_OBJECTS. This parameter cannot be zero.
See here for a discussion.
It might be worth checking what the wait function has returned too.
I would allocate a struct before calling _beginthreadex and pass the pointer to the struct through the threads parameter and have the struct contain a bool which is set by the thread when it's done.
struct ThreadStruct{
bool Done;
char* ParamData;
int ParamDataSize;
};
int ThreadIp(void* param)
{
ThreadStruct* ts = (ThreadStruct*)param;
while(true)
{
printf("I'm runing!\n");
}
ts->Done = true;
return 0;
}
int main()
{
int iThreadNum=100;
HANDLE* phThreads = new HANDLE[iThreadNum];
ThreadStruct* structs = new ThreadStruct[iThreadNum];
for (int i=0;i<iThreadNum;++i)
{
ZeroMemory(structs[i], sizeof(ThreadStruct));
phThreads[i]=(HANDLE*)_beginthreadex(NULL, 0, (THREAD_FUN_TYPE)ThreadIp, structs[i], NULL, NULL);
ResetEvent(phThreads[i]);
}
for(unsigned int i=0; i<iThreadNum;){
if(!structs[i]->Done) i=0;
else i++;
}
printf("End!\n");
return 0;
}
When unhandled exception occured i want to print a stacktrace instead of just terminating. I've tried to do that using SetUnhandledExceptionFilter:
SetUnhandledExceptionFilter(UnhandledException);
...
LONG WINAPI UnhandledException(LPEXCEPTION_POINTERS exceptionInfo)
{
printf("An exception occurred which wasn't handled!\nCode: 0x%08X\nAddress: 0x%08X",
exceptionInfo->ExceptionRecord->ExceptionCode,
exceptionInfo->ExceptionRecord->ExceptionAddress);
return EXCEPTION_EXECUTE_HANDLER;
}
This code, i've found, works fine. However there are no addition information because ExceptionCode and ExceptionAddress are printed in system "Event Viewer" anyway.
If it is possible to print a full stack trace so I can determine the exact point where exception occured?
I've found this code https://code.google.com/p/m0d-s0beit-sa/source/browse/src/main.cpp?r=9ceb4fec21d647b169c72851d7882bef2b9c5a8a It partly solves my problem. Only method where exception occured is printed. But type of exception and line number is not printed.
Here's some stack-walk code for Windows I wrote some years ago. Here's the kind of output it produces:
Walking stack.
0 DebugBreak
1 ThreadFunc2 e:\c\source\stackwalk2a.cpp(72)
2 ThreadFunc1 e:\c\source\stackwalk2a.cpp(79)
3 TargetThread e:\c\source\stackwalk2a.cpp(86)
4 BaseThreadInitThunk
5 RtlUserThreadStart
End of stack walk.
The main thing that's missing is anything about the exception type. If you're talking about a native structured/vectored exception, I'm pretty sure that should be retrievable too. Retrieving types of C++ exceptions might be a little more difficult (but I'm not really sure -- it might be pretty easy).
#include <windows.h>
#include <winnt.h>
#include <string>
#include <vector>
#include <Psapi.h>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <iterator>
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "dbghelp.lib")
// Some versions of imagehlp.dll lack the proper packing directives themselves
// so we need to do it.
#pragma pack( push, before_imagehlp, 8 )
#include <imagehlp.h>
#pragma pack( pop, before_imagehlp )
struct module_data {
std::string image_name;
std::string module_name;
void *base_address;
DWORD load_size;
};
typedef std::vector<module_data> ModuleList;
HANDLE thread_ready;
bool show_stack(std::ostream &, HANDLE hThread, CONTEXT& c);
DWORD __stdcall TargetThread( void *arg );
void ThreadFunc1();
void ThreadFunc2();
DWORD Filter( EXCEPTION_POINTERS *ep );
void *load_modules_symbols( HANDLE hProcess, DWORD pid );
int main( void ) {
DWORD thread_id;
thread_ready = CreateEvent( NULL, false, false, NULL );
HANDLE thread = CreateThread( NULL, 0, TargetThread, NULL, 0, &thread_id );
WaitForSingleObject( thread_ready, INFINITE );
CloseHandle(thread_ready);
return 0;
}
// if you use C++ exception handling: install a translator function
// with set_se_translator(). In the context of that function (but *not*
// afterwards), you can either do your stack dump, or save the CONTEXT
// record as a local copy. Note that you must do the stack dump at the
// earliest opportunity, to avoid the interesting stack-frames being gone
// by the time you do the dump.
DWORD Filter(EXCEPTION_POINTERS *ep) {
HANDLE thread;
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &thread, 0, false, DUPLICATE_SAME_ACCESS);
std::cout << "Walking stack.";
show_stack(std::cout, thread, *(ep->ContextRecord));
std::cout << "\nEnd of stack walk.\n";
CloseHandle(thread);
return EXCEPTION_EXECUTE_HANDLER;
}
void ThreadFunc2() {
__try { DebugBreak(); }
__except (Filter(GetExceptionInformation())) { }
SetEvent(thread_ready);
}
void ThreadFunc1(void (*f)()) {
f();
}
// We'll do a few levels of calls from our thread function so
// there's something on the stack to walk...
//
DWORD __stdcall TargetThread(void *) {
ThreadFunc1(ThreadFunc2);
return 0;
}
class SymHandler {
HANDLE p;
public:
SymHandler(HANDLE process, char const *path=NULL, bool intrude = false) : p(process) {
if (!SymInitialize(p, path, intrude))
throw(std::logic_error("Unable to initialize symbol handler"));
}
~SymHandler() { SymCleanup(p); }
};
#ifdef _M_X64
STACKFRAME64 init_stack_frame(CONTEXT c) {
STACKFRAME64 s;
s.AddrPC.Offset = c.Rip;
s.AddrPC.Mode = AddrModeFlat;
s.AddrStack.Offset = c.Rsp;
s.AddrStack.Mode = AddrModeFlat;
s.AddrFrame.Offset = c.Rbp;
s.AddrFrame.Mode = AddrModeFlat;
return s;
}
#else
STACKFRAME64 init_stack_frame(CONTEXT c) {
STACKFRAME64 s;
s.AddrPC.Offset = c.Eip;
s.AddrPC.Mode = AddrModeFlat;
s.AddrStack.Offset = c.Esp;
s.AddrStack.Mode = AddrModeFlat;
s.AddrFrame.Offset = c.Ebp;
s.AddrFrame.Mode = AddrModeFlat;
return s;
}
#endif
void sym_options(DWORD add, DWORD remove=0) {
DWORD symOptions = SymGetOptions();
symOptions |= add;
symOptions &= ~remove;
SymSetOptions(symOptions);
}
class symbol {
typedef IMAGEHLP_SYMBOL64 sym_type;
sym_type *sym;
static const int max_name_len = 1024;
public:
symbol(HANDLE process, DWORD64 address) : sym((sym_type *)::operator new(sizeof(*sym) + max_name_len)) {
memset(sym, '\0', sizeof(*sym) + max_name_len);
sym->SizeOfStruct = sizeof(*sym);
sym->MaxNameLength = max_name_len;
DWORD64 displacement;
if (!SymGetSymFromAddr64(process, address, &displacement, sym))
throw(std::logic_error("Bad symbol"));
}
std::string name() { return std::string(sym->Name); }
std::string undecorated_name() {
std::vector<char> und_name(max_name_len);
UnDecorateSymbolName(sym->Name, &und_name[0], max_name_len, UNDNAME_COMPLETE);
return std::string(&und_name[0], strlen(&und_name[0]));
}
};
bool show_stack(std::ostream &os, HANDLE hThread, CONTEXT& c) {
HANDLE process = GetCurrentProcess();
int frame_number=0;
DWORD offset_from_symbol=0;
IMAGEHLP_LINE64 line = {0};
SymHandler handler(process);
sym_options(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
void *base = load_modules_symbols(process, GetCurrentProcessId());
STACKFRAME64 s = init_stack_frame(c);
line.SizeOfStruct = sizeof line;
IMAGE_NT_HEADERS *h = ImageNtHeader(base);
DWORD image_type = h->FileHeader.Machine;
do {
if (!StackWalk64(image_type, process, hThread, &s, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
return false;
os << std::setw(3) << "\n" << frame_number << "\t";
if ( s.AddrPC.Offset != 0 ) {
std::cout << symbol(process, s.AddrPC.Offset).undecorated_name();
if (SymGetLineFromAddr64( process, s.AddrPC.Offset, &offset_from_symbol, &line ) )
os << "\t" << line.FileName << "(" << line.LineNumber << ")";
}
else
os << "(No Symbols: PC == 0)";
++frame_number;
} while (s.AddrReturn.Offset != 0);
return true;
}
class get_mod_info {
HANDLE process;
static const int buffer_length = 4096;
public:
get_mod_info(HANDLE h) : process(h) {}
module_data operator()(HMODULE module) {
module_data ret;
char temp[buffer_length];
MODULEINFO mi;
GetModuleInformation(process, module, &mi, sizeof(mi));
ret.base_address = mi.lpBaseOfDll;
ret.load_size = mi.SizeOfImage;
GetModuleFileNameEx(process, module, temp, sizeof(temp));
ret.image_name = temp;
GetModuleBaseName(process, module, temp, sizeof(temp));
ret.module_name = temp;
std::vector<char> img(ret.image_name.begin(), ret.image_name.end());
std::vector<char> mod(ret.module_name.begin(), ret.module_name.end());
SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size);
return ret;
}
};
void *load_modules_symbols(HANDLE process, DWORD pid) {
ModuleList modules;
DWORD cbNeeded;
std::vector<HMODULE> module_handles(1);
EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
module_handles.resize(cbNeeded/sizeof(HMODULE));
EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(process));
return modules[0].base_address;
}
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.