I am writing to write a program that will make use of multithreading. I tried to read about multithreading and was able to get a sample program working. However I have run into a glitch and I am not sure what is going wrong. I am posting the sample program and will highlight where I am experiencing trouble.
#include <Windows.h>
#include <process.h>
#include <iostream>
#include <cassert>
#include <ctime>
#import "calc.dll" \
auto_rename no_namespace no_smart_pointers \
raw_native_types named_guids
using namespace std;
HANDLE th_mutex;
struct Arguments
{
string case_id;
string file;
};
//____________________________________
unsigned int __stdcall TestThread(void *args)
{
int i = 0,
j = 0;
cout << "Inside thread" << endl;
for (i = 0; i <= 10000; i++)
{
for (j = 0; j <= 100000; j++)
{
}
if (i == 10000)
cout << "The value of i inside the thread = " << i << endl;
}
return EXIT_SUCCESS;
}
//____________________________________
unsigned int __stdcall Thread(void *args)
{
CoInitialize(0);
{
Arguments *input;
input = (Arguments *) args;
time_t current_time;
time(¤t_time);
cout << ctime(¤t_time) << endl;
IHeatExchangerNetwork *hxNetwork = 0;
IDispatchPtr theUnit = 0;
IHeatTransferUnit *unit = 0;
VARIANT vAppend;
_bstr_t filename,
output;
filename = input->file.c_str();
filename += input->case_id.c_str();
filename += ".dat";
output = input->file.c_str();
output += input->case_id.c_str();
output += ".dbo";
cout << filename << endl;
cout << output << endl;
HRESULT hr = CoCreateInstance(CLSID_HeatExchangerNetwork,
0,
CLSCTX_ALL,
DIID_IHeatExchangerNetwork,
reinterpret_cast<void**>(&hxNetwork));
theUnit = hxNetwork->LoadHeatTransferUnit(filename, HxUnitTypeKey::HxUnitTypeCrossflow);
hr = theUnit->QueryInterface(DIID_IHeatTransferUnit, reinterpret_cast<void**>(&unit));
hxNetwork->Run(0, 0);
vAppend.boolVal = false;
unit->WriteDBOFile(output, OutputData, vAppend);
time(¤t_time);
cout << ctime(¤t_time) << endl;
}
CoUninitialize();
return EXIT_SUCCESS;
}
//____________________________________
int main()
{
DWORD retval;
Arguments args[2];
args[0].case_id = "1";
args[0].file = "C:\\Documents and Settings\\User\\My Documents\\Test Cases\\1\\";
args[1].case_id = "2";
args[1].file = "C:\\Documents and Settings\\User\\My Documents\\Test Cases\\2\\";
th_mutex = CreateMutex(NULL, FALSE, NULL);
if (th_mutex == NULL)
{
printf("CreateMutex error: %d\n", GetLastError());
return 1;
}
// ================================
// Basic testing of calling threads
// ================================
HANDLE hnd1;
cout << "Before creating new thread" << endl;
hnd1 = (HANDLE) _beginthreadex(NULL, 0, &TestThread, NULL, 0, 0);
cout << "After creating thread" << endl;
// ====================================
// Calling Calc routine through threads
// ====================================
HANDLE hnd2,
hnd3;
hnd2 = (HANDLE) _beginthreadex(NULL,
0,
&Thread,
(void *)&args[0],
0,
0);
hnd3 = (HANDLE) _beginthreadex(NULL,
0,
&Thread,
(void *)&args[1],
0,
0);
WaitForSingleObject(hnd1, INFINITE);
WaitForSingleObject(hnd2, INFINITE);
WaitForSingleObject(hnd3, INFINITE);
GetExitCodeThread(hnd1, &retval); // Gets the return value from the function
CloseHandle(hnd1);
CloseHandle(hnd2);
CloseHandle(hnd3);
return EXIT_SUCCESS;
}
The problem I am facing is when I execute the program I get the following output
Before creating new thread
After creating threadInside thread
Thu Aug 09 10:56:58 2012
Thu Aug 09 10:56:58 2012
C:\Documents and Settings\User\My Documents\Test Cases\1\1.datC:\Documents and Settings\User
\My Documents\Test Cases\2\2.dat
C:\Documents and Settings\kcomandur\My Documents\Test Cases\1\1.dboC:\Documents and Settings\User
\My Documents\Test Cases\2\2.dbo
The value of i inside the thread = 10000
Thu Aug 09 10:57:08 2012
and then program crashes. I get the following error
Debug Error!
Program: ...MultiThreading.exe
R6010
-abort() has been called
(Press Retry to debug the application)
When I do a retry, the break occurs in the generated .tli file in the following location starting with _com_dispatch_method
#pragma implementation_key(723)
inline IDispatch * IHeatExchangerNetwork::LoadHeatTransferUnit ( BSTR filename, enum HxUnitTypeKey unitType ) {
IDispatch * _result = 0;
_com_dispatch_method(this, 0x20, DISPATCH_METHOD, VT_DISPATCH, (void*)&_result,
L"\x0008\x0003", filename, unitType);
return _result;
}
The filename variable has the value
C:\Documents and Settings\User\My Documents\Test Cases\2\2.dat
I tried using mutex and modified the Thread function
unsigned int __stdcall Thread(void *args)
{
CoInitialize(0);
{
WaitForSingleObject(th_mutex, INFINITE);
// Same content as original Thread function.
// Not writing it again to minimize space
ReleaseMutex(th_mutex);
}
CoUninitialize();
return EXIT_SUCCESS;
}
//____________________________________
This time the program crashes at the following location _com_dispatch_method in the .tli file
#pragma implementation_key(966)
inline long IHeatTransferUnit::WriteDBOFile ( BSTR filename, short io, const VARIANT & vAppend ) {
long _result = 0;
_com_dispatch_method(this, 0x32, DISPATCH_METHOD, VT_I4, (void*)&_result,
L"\x0008\x0002\x080c", filename, io, &vAppend);
return _result;
}
By using mutex the error is being generated by the thread which has the HANDLE hnd3. The variable filename has the value
C:\Documents and Settings\User\My Documents\Test Cases\2\2.dbo
Also by using mutex I was able to get past the previous error location.
I am not sure if I really need a mutex as the following call
hxNetwork->Run(0, 0);
works on two different files that are no way related to each other. Also this is the most time consuming portion of the program and hence I wanted to run 2 cases simultaneously.
By using mutex the way I did, it runs the first case and then the second case.
Also the I have no control over the calc.dll. It is a third part software and I am not sure if supports multithreading or not.
So I would like to know what I need to do to get both the runs going and also be able to output the 2 files
Thanks in advance
Related
I am studying the Thread Ordering Service of Windows. So, I have written the following code to test how TOS works really? But it doesn't work and it gives me an error.
#include <windows.h>
#include <process.h>
#include <iostream>
#include <avrt.h>
#include <stdio.h>
#pragma comment(lib, "Avrt.lib")
#define _100NS_IN_1MS 10000
unsigned __stdcall Thread1(void* arg_list)
{
for (size_t i = 0; i < 100; i++)
{
std::cout << "\tHello from Thread1, Repeat #" << i + 1 << std::endl;
SwitchToThread();
}
return 0;
}
unsigned __stdcall Thread2(void* arg_list)
{
for (size_t i = 0; i < 100; i++)
{
std::cout << "\tHello from Thread2, Repeat #" << i + 1 << std::endl;
}
return 0;
}
int main()
{
HANDLE handle_context = NULL;
LARGE_INTEGER period, timeout;
GUID guid = { 0 };
BOOL result;
period.QuadPart = Int32x32To64(_100NS_IN_1MS, 1000); // 1 second
timeout.QuadPart = Int32x32To64(_100NS_IN_1MS, 10000); // 10 seconds
result = AvRtCreateThreadOrderingGroup(&handle_context, &period, &guid, &timeout);
if (result != TRUE)
{
printf("Error creating group (%d)\n", GetLastError());
return 1;
}
HANDLE handle_thread1 = (HANDLE)_beginthreadex(NULL, 0, Thread1, NULL, CREATE_SUSPENDED, NULL);
HANDLE handle_thread2 = (HANDLE)_beginthreadex(NULL, 0, Thread2, NULL, CREATE_SUSPENDED, NULL);
AvRtJoinThreadOrderingGroup(&handle_thread1, &guid, FALSE);
AvRtJoinThreadOrderingGroup(&handle_thread2, &guid, FALSE);
if (handle_thread1 == NULL && handle_thread2 == NULL)
{
return -1;
}
ResumeThread(handle_thread1);
ResumeThread(handle_thread2);
int recieve1 = WaitForSingleObject(handle_thread1, INFINITE);
int recieve2 = WaitForSingleObject(handle_thread2, INFINITE);
CloseHandle(handle_thread1);
CloseHandle(handle_thread2);
}
When I run the above program, it gives me the following error:
Error creating group (1058)
1058 (0x422)
The service cannot be started, either because it is disabled or
because it has no enabled devices associated with it.
What should I do now? I am using Windows 10.
The links here and here, explain that Windows Thread Ordering Service is not on by default:
The thread ordering service is off by default and must be started by
the user. While the thread ordering service is running, it is
activated every 5 seconds to check whether there is a new request,
even if the system is idle. This prevents the system from sleeping for
longer than 5 seconds, causing the system to consume more power. If
energy efficiency is critical to the application, it is better not to
use the thread ordering service and instead allow the system scheduler
to manage execution of threads.
Use cases and other discussion are also discussed and code snippets are provided in some of the other links (see 2nd link above.) Following is an example:
#include <windows.h>
#include <avrt.h>
#include <stdio.h>
#pragma comment(lib, "Avrt.lib")
#define _100NS_IN_1MS 10000
int main( void )
{
HANDLE hContext = NULL;
LARGE_INTEGER period, timeout;
GUID guid = { 0 };
BOOL bRes;
period.QuadPart = Int32x32To64(_100NS_IN_1MS, 1000); // 1 second
timeout.QuadPart = Int32x32To64(_100NS_IN_1MS, 10000); // 10 seconds
bRes = AvRtCreateThreadOrderingGroup(
&hContext,
&period,
&guid,
&timeout );
if( bRes != TRUE )
{
printf("Error creating group (%d)\n", GetLastError());
return 1;
}
return 0;
}
Context:
I need to scan for, gather information and copy some media files from specific directories.
I have been having quite some trouble with some files not being detected, etc
Problem:
Warning to reader: As seen on the screenshot and noted in a comment,
the title and premise of this question are possible moot, as the error
was more likely to be dec 32 (== 0x20) == ERROR_SHARING_VIOLATION,
which has an "easy" explantion in the answer to this question.
In the code below, I use a c-style cast to convert my QString into a LPCWSTR for the CopyFileExW which I found in this SO post. I have tried many different conversions, but non of them seems to work correctly - which for now is besides the point.
The problem this 'conversion' technique gives is the error ERROR_NOT_SUPPORTED
ERROR_NOT_SUPPORTED
50 (0x32)
The request is not supported.
Frankly, this makes absolutely no sense to me in this context. I am copying from NTFS -> NTFS (same hard drive for testing), with destination file length < 200 characters (see image, 192 to be exact).
The core code: (see bottom for full details)
// QString src (src file location), dst (destination file location)
LPCWSTR localC_src = (LPCWSTR) src.utf16();
LPCWSTR localC_dst = (LPCWSTR) dst.utf16();
LPCWSTR dirC = (LPCWSTR) dir.utf16();
auto rc = CopyFileExW(localC_src, localC_dst, &BackupManager::copyProgress, this, &bStopBackup, 0);
if (rc == 0) {
DWORD lastError = GetLastError(); // Error = 0x32
bool dirExist = DirExists(dirC); // true
bool fileExists = FileExists(localC_src); // true
printWarning(TAG, QString("File Copy Error: %1").arg(getLastErrorMsg()));
#ifdef QT_DEBUG
if (FileExists(localC_src)) {
qDebug() << "#FailedCopy: Windows file exists but copy failed" << src; // this gets hit using the implemented c-style cast
}
else {
if (QFile::exists(src)) {
qDebug() << "#FailedCopy: Windows is really being full of shit! " << src; // this always gets triggered when using QString::toStdWString.c_str()
}
else {
qDebug() << "#FailedCopy: Windows file copy failed outright" << src;
}
}
// ...
} else {
// success
}
What does this error mean in the FileCopyExW context?
(also, if anyone has the source for windows.h implementation to allow me to trace the error further, please post it as a comment)
Image of debugger, etc
Full Code Implemenation:
static QString toString(HRESULT hr)
{
_com_error err{hr};
const TCHAR* lastError = err.ErrorMessage();
return QStringLiteral("Error 0x%1: %2").arg((quint32)hr, 8, 16, QLatin1Char('0'))
.arg(lastError);
}
static QString getLastErrorMsg()
{
DWORD lastError = GetLastError();
QString s = toString(HRESULT_FROM_WIN32(lastError));
return s;
}
BOOL FileExists(LPCWSTR szPath)
{
DWORD dwAttrib = GetFileAttributes(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
// not used
static const wchar_t* toLPCWSTR(QString s)
{
std::wstring dstWString = s.toStdWString();
const wchar_t* localC_src = dstWString.c_str();
return localC_src;
}
static bool DirExists(LPCWSTR szPath)
{
DWORD ftyp = GetFileAttributes(szPath);
if (ftyp == INVALID_FILE_ATTRIBUTES)
return false; //something is wrong with your path!
if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
return true; // this is a directory!
return false; // this is not a directory!
}
BackupResult BackupManager::copyFile(QString m_src, QString m_dst)
{
QFileInfo fi(m_src);
QString dir = fi.dir().path();
// const wchar_t* dirC = toLPCWSTR(dir);
QString src = QString(m_src).replace("/", "\\");
QString dst = QString(m_src).replace("/", "\\");
// const wchar_t* localC_src = toLPCWSTR(src);
// const wchar_t* localC_dst = toLPCWSTR(dst);
LPCWSTR localC_src = (LPCWSTR) src.utf16();
LPCWSTR localC_dst = (LPCWSTR) dst.utf16();
LPCWSTR dirC = (LPCWSTR) dir.utf16();
auto rc = CopyFileExW(localC_src, localC_dst, &BackupManager::copyProgress, this, &bStopBackup, 0);
if (rc == 0) {
DWORD lastError = GetLastError(); // Error = 0x32
bool dirExist = DirExists(dirC); // true
bool fileExists = FileExists(localC_src); // true
printWarning(TAG, QString("File Copy Error: %1").arg(getLastErrorMsg()));
#ifdef QT_DEBUG
if (FileExists(localC_src)) {
qDebug() << "#FailedCopy: Windows file exists but copy failed" << src; // this gets hit using the implemented c-style cast
}
else {
if (QFile::exists(src)) {
qDebug() << "#FailedCopy: Windows is really being full of shit! " << src; // this always gets triggered when using QString::toStdWString.c_str()
}
else {
qDebug() << "#FailedCopy: Windows file copy failed outright" << src;
}
}
#endif
// copy failed
return BackupResult::IOError;
}
// copy success
return BackupResult::Success;
}
I suggest you check whether the copied file handle is opened in another process.
I created a simple sample, the code is as follows:
#include <iostream>
#include <Windows.h>
using namespace std;
int main(int argc, const char* argv[])
{
CopyFileEx(L"D:\\test\\test.txt", L"D:\\test\\test2.txt", NULL, NULL, 0, 0);
int e = GetLastError();
cout << "error code is :" << e << endl;
return 0;
}
This sample of course successfully copied the file.But if I add the code to open the handle of this file, it will return error code 32.
#include <iostream>
#include <Windows.h>
using namespace std;
int main(int argc, const char* argv[])
{
CreateFileW(L"D:\\test\\test.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
CopyFileEx(L"D:\\test\\test.txt", L"D:\\test\\test2.txt", NULL, NULL, 0, 0);
int e = GetLastError();
cout << "error code is :" << e << endl;
return 0;
}
Outout:
So I think you did not close it properly after opening the handle in other locations. If you need to copy files while the handle is open, you can modify the dwShareMode parameter to FILE_SHARE_READ. In this way, the file copy operation can be performed when the handle is opened.
Here is the sample:
#include <iostream>
#include <Windows.h>
using namespace std;
int main(int argc, const char* argv[])
{
CreateFileW(L"D:\\test\\test.txt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
CopyFileEx(L"D:\\test\\test.txt", L"D:\\test\\test2.txt", NULL, NULL, 0, 0);
int e = GetLastError();
cout << "error code is :" << e << endl;
return 0;
}
Output:
More reference:CreateFileW and CopyFileExA
I am doing my first steps in C++ multi threading and ran into a problem.
What I wouyld like to achieve is set out tasks with parameters that will be running in separate threads.
Googling for answers did not bring me the answer.
The system I am using consists of Windows 10 Pro, and Code::Blocks 20.3 with MinGW 17.1
I have created a simple example to get a feeling for it.
The first example (a single cpp file) works just fine.
The second however (in a class) has build errors even though I am using the same code.
I hope someone can explain the reasons why, and hopefully shows me how to solve thsi.
First (working) example:
#include <windows.h>
#include <process.h>
#include <iostream>
#include <chrono>
#include <thread>
struct Param
{
std::string param1;
};
unsigned Counter;
unsigned __stdcall DoSomething( void *ptr )
{
std::cout << "In second thread...\n";
Param *p_tmp = reinterpret_cast<Param*>(ptr);
Param p_param = *p_tmp;
std::string result = p_param.param1;
while ( Counter < 1000 )
{
Counter++;
std::cout << result << Counter << '\r';
std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
std::cout << std::endl;
_endthreadex( 0 );
return 0;
}
void CreateThread()
{
HANDLE hThread;
unsigned threadID;
std::string result{"Count: "};
Param param;
param.param1 = "Count: ";
std::cout << "Main thread\nCreating second thread...\n";
// Create the second thread.
hThread = (HANDLE)_beginthreadex( NULL, 0, &DoSomething, (void*)¶m, 0, &threadID );
// Wait until second thread terminates
WaitForSingleObject( hThread, INFINITE );
std::cout << "Returned to Main thread\nCounter should be 1000; it is-> "<< Counter << std::endl;
// Destroy the thread object.
CloseHandle( hThread );
}
int main()
{
CreateThread();
}
The second example (in a class):
struct Param
{
std::string param1;
};
unsigned Counter;
void CthreadFrame::CreateThread()
{
HANDLE hThread;
unsigned threadID;
Param param;
param.param1 = "Count: ";
std::cout << "Main thread\nCreating second thread...\n";
// Create the second thread
hThread = (HANDLE)_beginthreadex( NULL, 0, &DoSomething, (void*)¶m, 0, &threadID );
// Wait for second thread to terminate
WaitForSingleObject( hThread, INFINITE );
std::cout << "Returned to Main thread\nCounter should be 1000; it is-> "<< Counter << std::endl;
// Destroy the thread object.
CloseHandle( hThread );
/* End of void CreateThread */
}
unsigned __stdcall CthreadFrame::DoSomething(void *ptr)
{
std::cout << "In second thread...\n";
Param *p_tmp = reinterpret_cast<Param*>(ptr);
Param p_param = *p_tmp;
std::string result = p_param.param1;
while ( Counter < 1000 )
{
Counter++;
std::cout << result << Counter << '\r';
std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
std::cout << std::endl;
_endthreadex( 0 );
return 0;
}
Build Messages:
||=== Build: Debug in Cthread (compiler: GNU GCC Compiler) ===|
F:\Data\__C++\wxApps\Cthread\CthreadMain.cpp||In member function 'void CthreadFrame::CreateThread()':|
F:\Data\__C++\wxApps\Cthread\CthreadMain.cpp|114|error: cannot convert 'unsigned int (CthreadFrame::*)(void*)' to '_beginthreadex_proc_type' {aka 'unsigned int (*)(void*)'}|
f:\sdks\mingw-17.1\x86_64-w64-mingw32\include\process.h|37|note: initializing argument 3 of 'uintptr_t _beginthreadex(void*, unsigned int, _beginthreadex_proc_type, void*, unsigned int, unsigned int*)'|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 2 second(s)) ===|
Just declare your thread function as static function:
class CthreadFrame
{
public:
void Start() {
m_hThread = (HANDLE)_beginthreadex(
nullptr, 0, &CthreadFrame::DoSomething,
this /* store params here */, 0, &m_uThreadId
);
}
private:
static unsigned __stdcall DoSomething(void*);
private:
HANDLE m_hThread;
unsigned m_uThreadId;
};
Thank you Georgy Firsov.
I would never have thought searching for std::msm_fn without your help.
I changed my code to:
std::thread th(std::mem_fn(&CthreadFrame::DoSomething), std::ref(*this), (void *)¶m );
th.join();
And that did the trick. Now I can pass all sorts of variables to a thread function.
So I was making an application using C++ Console, with multi threading as below, then I got an error 0x0000005.
The first time it run it was working as usual. Can anyone help me with this problem?
I am using Code::Blocks IDE with Borland C++ 5.5, and I am planning to make this into Borland C++ 5.02
#include <windows.h>
#include <stdio.h>
#include <dos.h>
#include <iostream.h>
#include <conio.h>
void linesmov(int mseconds, int y);
void linesmov(int mseconds, int y)
{
int i=0;
while (true)
{
i=i+1;
// Or system("cls"); If you may...
gotoxy(i,y);
cout << "____||____||____";
gotoxy(i-1,y);
cout << " ";
Sleep(mseconds);
if (i>115)
{
i=0;
for(int o = 0; o < 100; o++)
{
gotoxy(0,y);
cout << " ";
}
}
}
}
DWORD WINAPI mythread1(LPVOID lpParameter)
{
printf("Thread inside %d \n", GetCurrentThreadId());
linesmov(5,10);
return 0;
}
DWORD WINAPI mythread2(LPVOID lpParameter)
{
printf("Thread inside %d \n", GetCurrentThreadId());
linesmov(30,15);
return 0;
}
int main(int argc, char* argv[])
{
HANDLE myhandle1;
DWORD mythreadid1;
HANDLE myhandle2;
DWORD mythreadid2;
myhandle1 = CreateThread(0,0,mythread1,0,0,&mythreadid1);
myhandle2 = CreateThread(0,0,mythread2,0,0,&mythreadid2);
printf("Thread after %d \n", mythreadid1);
getchar();
return 0;
}
All of these solutions in comments including mine are definitely not the way how it should be done. The main problem is lack of synchronization between threads and lack of processing their termination. Also, every function should be checked for thread-safe compatibility or should be wrapped to match it.
Considering std::cout since c++11 we have some data race guarantees:
Concurrent access to a synchronized (§27.5.3.4) standard iostream
object’s formatted and unformatted input (§27.7.2.1) and output
(§27.7.3.1) functions or a standard C stream by multiple threads shall
not result in a data race (§1.10). [ Note: Users must still
synchronize concurrent use of these objects and streams by multiple
threads if they wish to avoid interleaved characters. — end note ]
So lask of synchronization primitives is oblivious according to this note.
Considering processing of thread termination.
HANDLE threadH = CreateThread(...);
...
TerminateThread(threadH, 0); // Terminates a thread.
WaitForSingleObject(threadH, INFINITE); // Waits until the specified object is in the signaled state or the time-out interval elapses.
CloseHandle(threadH); // Closes an open object handle.
TerminateThread(), but be aware of this solution, because ..
WaitForSingleObject()
And this is only first steps to thread-safe way.
I would like to recommend C++ Concurrency in Action: Practical Multithreading by Anthony Williams for further reading.
Rude solution for synchronized output
#include <Windows.h>
#include <iostream>
#include <mutex>
std::mutex _mtx; // global mutex
bool online = true; // or condition_variable
void gotoxy(int x, int y)
{
COORD c = { x, y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
void linesmov(int mseconds, int y) {
int i = 0;
while (online) {
i = i + 1;
// Or system("cls"); If you may...
_mtx.lock(); // <- sync here
gotoxy(i, y);
std::cout << "____||____||____"; gotoxy(i - 1, y);
std::cout << " ";
_mtx.unlock();
Sleep(mseconds);
if (i > 75)
{
i = 0;
for (int o = 0; o < 60; o++)
{
_mtx.lock(); // <- sync here
gotoxy(0, y);
std::cout << " ";
_mtx.unlock();
}
}
}
}
DWORD WINAPI mythread1(LPVOID lpParameter)
{
std::cout << "Thread 1" << GetCurrentThreadId() << std::endl;
linesmov(5, 10);
return 0;
}
DWORD WINAPI mythread2(LPVOID lpParameter)
{
std::cout << "Thread 2" << GetCurrentThreadId() << std::endl;
linesmov(30, 15);
return 0;
}
int main(int argc, char* argv[])
{
DWORD mythreadid1;
DWORD mythreadid2;
HANDLE myhandle1 = CreateThread(0, 0, mythread1, 0, 0, &mythreadid1);
HANDLE myhandle2 = CreateThread(0, 0, mythread2, 0, 0, &mythreadid2);
std::cout << "Base thread: " << GetCurrentThreadId() << std::endl;
getchar();
online = false;
WaitForSingleObject(myhandle1, INFINITE);
WaitForSingleObject(myhandle2, INFINITE);
CloseHandle(myhandle1);
CloseHandle(myhandle2);
return 0;
}
a) Both gotoxy not outputting via std::cout are not thread safe /synchronized. You need process-wide mutex to synchronize that
b) exception is likely due to fact that you do not use WaitForMultipleObjects in main to wait for threads to finish. Depending on hardware and optimization main may exit before threads finish their work.
I'm trying to get the path of a device by using the SetupDiGetDeviceInterfaceDetail() function, but it crashes everytime I call it. I've have been working on this for over 12 hours but still couldn't find out what is wrong with it... Can someone see if they can find what is actually causing this to happen? Heres the code:
//DeviceManager.h
#include <windows.h>
//#include <hidsdi.h>
#include <setupapi.h>
#include <iostream>
#include <cfgmgr32.h>
#include <tchar.h>
#include <devpkey.h>
#include <string>
extern "C"{
#include <hidsdi.h>
}
//#pragma comment (lib, "setupapi.lib")
class DeviceManager
{
public:
DeviceManager();
~DeviceManager();
void ListAllDevices();
void GetDeviceHandler();
//HANDLE PSMove;
//byte reportBuffer[57];
GUID guid;
//private:
HDEVINFO deviceInfoSet; //A list of all the devices
SP_DEVINFO_DATA deviceInfoData; //A device from deviceInfoSet
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData;
};
//DeviceManager.cpp
#include"DeviceManager.h"
DeviceManager::DeviceManager()
{
//deviceInterfaceData = new SP_DEVICE_INTERFACE_DATA;
//deviceInterfaceDetailedData = new SP_DEVICE_INTERFACE_DETAIL_DATA;
HidD_GetHidGuid(&guid);
deviceInfoSet = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); //Gets all Devices
GetDeviceHandler();
}
DeviceManager::~DeviceManager()
{
}
void DeviceManager::ListAllDevices()
{
DWORD deviceIndex = 0;
deviceInfoData.cbSize = sizeof(deviceInfoData);
while(SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, &deviceInfoData))
{
deviceInfoData.cbSize = sizeof(deviceInfoData);
ULONG tcharSize;
CM_Get_Device_ID_Size(&tcharSize, deviceInfoData.DevInst, 0);
TCHAR* deviceIDBuffer = new TCHAR[tcharSize]; //the device ID will be stored in this array, so the tcharSize needs to be big enough to hold all the info.
//Or we can use MAX_DEVICE_ID_LEN, which is 200
CM_Get_Device_ID(deviceInfoData.DevInst, deviceIDBuffer, MAX_PATH, 0); //gets the devices ID - a long string that looks like a file path.
std::cout << deviceIDBuffer << std::endl;
deviceIndex++;
}
}
void DeviceManager::GetDeviceHandler()
{
DWORD deviceIndex = 0;
SP_DEVINFO_DATA deviceInfoData;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData;
deviceInfoData.cbSize = sizeof(deviceInfoData);
while(SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, &deviceInfoData))
{
TCHAR deviceID[MAX_DEVICE_ID_LEN];
CM_Get_Device_ID(deviceInfoData.DevInst, deviceID, MAX_DEVICE_ID_LEN, 0);
//std::cout << deviceID << std::endl;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if(SetupDiEnumDeviceInterfaces(deviceInfoSet, &deviceInfoData, &guid, 0, &deviceInterfaceData))
{
DWORD bufferLength = 0;
//deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
deviceInterfaceData.cbSize = 2048;
//std::cout << "it works not" << std::endl;
if(SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, NULL, 0, &bufferLength, NULL))
{
//deviceInterfaceData.cbSize = sizeof(bufferLength);
std::cout << "It works!" << std::endl;
}
else
{
std::cout << GetLastError() << std::endl;
}
}
else
{
//std::cout << GetLastError() << std::endl;
}
deviceIndex++;
}
}
//mainapp.cpp
#pragma once
int main()
{
DeviceManager deviceManager;
return 0;
}
The SetupDiGetDeviceInterfaceDetail function is called in the GetDeviceHandler() function of DeviceManager.
Please help. Thanks.
UPDATE: I have found out that it failed on the first SetupDiGetDeviceInterfaceDetail and is returning a 122 error (ERROR_INSUFFICIENT_BUFFER). But I am only trying to get the required buffer size, so how can this be??
UPDATE 2: right, I have changed the function a bit (see above code) by setting the deviceInterfaceData.cbsize to 2048 (a huge space for testing purposes) and now I'm getting a ERROR_INVALID_PARAMETER. This is getting more and more confusing... How can the parameters I've given is invalid? Just doesn't make sense. The only difference is I passed in References instead of Pointers because otherwise I will get a access violation error...
Having found this topic, I'd like to share my problem that using exactly the same source, I got ERROR_INVALID_USER_BUFFER from the call.
The reason was the line:
deviceInterfaceDetailedData->cbSize =
sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
which on my quadbyte aligned compiler set the value 8 instead of the required value 5.
You're not allocating memory properly for the SP_DEVICE_INTERFACE_DETAIL_DATA.
Remove SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData; and try putting this inside your if block:
// Get the required bufferLength
SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
&deviceInterfaceData,
nullptr,
0,
&bufferLength,
nullptr);
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
std::cout << "Failed to get bufferLength. Error "
<< GetLastError() << '\n';
return;
}
// Create device interface detailed information struct pointer
// and allocate memory to it.
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData(nullptr);
deviceInterfaceDetailedData =
static_cast<PSP_INTERFACE_DEVICE_DETAIL_DATA>(malloc(bufferLength));
if(deviceInterfaceDetailedData == nullptr)
{
std::cout << "Failed to allocate memory. Error "
<< GetLastError() << '\n';
return;
}
deviceInterfaceDetailedData->cbSize =
sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
// Get detailed information
if(SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
&deviceInterfaceData,
deviceInterfaceDetailedData,
bufferLength,
&bufferLength,
nullptr))
{
//deviceInterfaceData.cbSize = sizeof(bufferLength);
std::cout << "It works!" << std::endl;
}
else
{
std::cout << GetLastError() << std::endl;
}
free(deviceInterfaceDetailedData);
I haven't looked at the rest of the code, it may have errors too, but this answers your original question.
This is according to MSDN definition:
Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with a NULLDeviceInterfaceDetailData pointer, a DeviceInterfaceDetailDataSize of zero, and a valid RequiredSize variable. In response to such a call, this function returns the required buffer size at RequiredSize and fails with GetLastError returning ERROR_INSUFFICIENT_BUFFER.
So, after ERROR_INSUFFICIENT_BUFFER error just use requiredSize value.