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.
Related
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);
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.
According to https://msdn.microsoft.com/en-us/library/hh567368.aspx
Magic statics (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm)
are supported on VS2015
However testing the following code in debug x64 Vs2015 Update 3
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <tchar.h>
#define MAX_THREADS 5
class Sleeper
{
public:
Sleeper()
{
std::cout << "Sleeper \n";
Sleep(100000);
}
};
DWORD WINAPI MyThreadFunction(LPVOID lpParam)
{
std::cout << "Sleeper Start" << (int)lpParam << "\n";
static Sleeper s;
std::cout << "Sleeper Done" << (int)lpParam << "\n";
return 0;
}
int main(int, char**)
{
DWORD dwThreadIdArray[MAX_THREADS];
HANDLE hThreadArray[MAX_THREADS];
// Create MAX_THREADS worker threads.
for (int i = 0; i<MAX_THREADS; i++)
{
// Create the thread to begin execution on its own.
hThreadArray[i] = CreateThread(
NULL, // default security attributes
0, // use default stack size
MyThreadFunction, // thread function name
(LPVOID)i, // argument to thread function
0, // use default creation flags
&dwThreadIdArray[i]); // returns the thread identifier
// Check the return value for success.
// If CreateThread fails, terminate execution.
// This will automatically clean up threads and memory.
if (hThreadArray[i] == NULL)
{
ExitProcess(3);
}
} // End of main thread creation loop.
// Wait until all threads have terminated.
WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);
// Close all thread handles and free memory allocations.
for (int i = 0; i<MAX_THREADS; i++)
{
CloseHandle(hThreadArray[i]);
}
return 0;
}
gives output
Sleeper Start0 Sleeper Sleeper Start2 Sleeper Start3 Sleeper Start1
Sleeper Start4
Which indicates that initializing static variable s is actually not thread safe.
Yes it does. The test was wrong. Removing the word sleeper from MyThreadFunction shows the expected output
Start1 Sleeper Start4 Start3 Start0 Start2 Done3 Done1 Done0 Done2
Done4
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
The following code compiles and runs on standard linux:
#include <iostream>
#include <pthread.h>
using namespace std;
class Foo
{
public:
Foo();
void go_thread();
void stop_thread();
private:
static void* worker( void* param );
pthread_t m_pt;
};
Foo::Foo()
{
m_pt = 0;
}
void Foo::go_thread()
{
int success = pthread_create( &m_pt, NULL, worker, static_cast<void*>(this) );
if( success == 0 )
{
cout << "thread started" << endl;
}
}
void Foo::stop_thread()
{
int success = pthread_join( m_pt, NULL );
if( success == 0 )
{
cout << "thread stopped" << endl;
}
}
void* Foo::worker( void* p )
{
cout << "thread running" << endl;
return 0;
}
int main()
{
Foo f;
f.go_thread();
f.stop_thread();
return 0;
}
and produces the following output:
$ ./a.out
thread started
thread running
thread stopped
$
This code also builds with the Android NDK (r5b). However, when I adb push the resulting executable to a device and run it, I get a SIGSEGV before main() even runs. I've isolated the issue down to pthread_create() It seems the mere existence of this call in my code, never mind execution, causes my prog to seg fault. Any ideas?
It may not be this but try making the function called by pthread create a normal c-function (i.e. declare it as extern "C") not a static member function:
This is because technically the calling convention for static members may be different from the C calling convention that is used by the C-library pthread (though a lot of the times they are the same (which is why it works on your linux box) in my opinion it is not worth the porting risk).
extern "C" void* start_the_thread(void*);
void* start_the_thread(void* data)
{
Foo* theObject = static_cast<Foo*>(data);
// In Java if your Foo had been derived from Runable
// This is s where theObject->run() would have been called.
return Foo::worker(data);
}
int success = pthread_create( &m_pt, NULL, start_the_thread, static_cast<void*>(this)
The issue seems to be combining iostream with pthread. I went through and replaced all couts with printf()s, removed the using clause, and removed the iostream header. The code compiled and ran with no issue on the device. I wonder if this is something Google should be made aware of?
The final (working) code looks like:
#include <pthread.h>
#include <stdio.h>
class Foo
{
public:
Foo();
void go_thread();
void stop_thread();
private:
static void* worker( void* param );
pthread_t m_pt;
};
Foo::Foo()
{
m_pt = 0;
}
void Foo::go_thread()
{
int success = pthread_create( &m_pt, NULL, worker, static_cast<void*>(this) );
if( success == 0 )
{
printf( "thread started\n" );
}
}
void Foo::stop_thread()
{
int success = pthread_join( m_pt, NULL );
if( success == 0 )
{
printf( "thread stopped\n" );
}
}
void* Foo::worker( void* p )
{
printf( "thread running\n" );
return 0;
}
int main()
{
Foo f;
f.go_thread();
f.stop_thread();
return 0;
}