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);
Related
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 can hook any other function, but not ExitProcess.
Here is the code to demonstrate this:
#include <iostream>
#include <cstdlib>
#include <Windows.h>
#include <Psapi.h>
void __stdcall NewSleep(DWORD milliseconds)
{
std::cout << "Sleep." << std::endl;
std::cin.get();
}
void __stdcall NewExitProcess(UINT exitCode)
{
std::cout << "ExitProcess." << std::endl;
std::cin.get();
}
FARPROC f1 = NULL;
FARPROC f2 = NULL;
int main()
{
HMODULE kernel32Module = GetModuleHandle("KERNEL32.dll");
f1 = GetProcAddress(kernel32Module, "Sleep");
f2 = GetProcAddress(kernel32Module, "ExitProcess");
std::cout << f1 << std::endl;
unsigned char* baseAddress = (unsigned char*)GetModuleHandle(NULL);
IMAGE_DOS_HEADER* idh = (IMAGE_DOS_HEADER*)baseAddress;
IMAGE_NT_HEADERS* inh = (IMAGE_NT_HEADERS*)(baseAddress + idh->e_lfanew);
IMAGE_IMPORT_DESCRIPTOR* iid = (IMAGE_IMPORT_DESCRIPTOR*)(baseAddress + inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
for (IMAGE_IMPORT_DESCRIPTOR* i = iid; i->Name != 0; ++i)
{
std::string moduleName = (char*)(baseAddress + i->Name);
if (moduleName == "KERNEL32.dll")
{
IMAGE_THUNK_DATA* itd = (IMAGE_THUNK_DATA*)(baseAddress + i->FirstThunk);
for (IMAGE_THUNK_DATA* j = itd; j->u1.Function != 0; ++j)
{
if ((FARPROC)j->u1.Function == f1)
{
DWORD oldProtect = 0;
VirtualProtect(&j->u1.Function, sizeof(DWORD), PAGE_READWRITE, &oldProtect);
j->u1.Function = (DWORD)&NewSleep;
VirtualProtect(&j->u1.Function, sizeof(DWORD), oldProtect, &oldProtect);
}
if ((FARPROC)j->u1.Function == f2)
{
DWORD oldProtect = 0;
VirtualProtect(&j->u1.Function, sizeof(DWORD), PAGE_READWRITE, &oldProtect);
j->u1.Function = (DWORD)&NewExitProcess;
VirtualProtect(&j->u1.Function, sizeof(DWORD), oldProtect, &oldProtect);
}
}
break;
}
}
Sleep(0);
Sleep(0);
ExitProcess(0);
//Crash.
std::cin.sync();
std::cin.get();
return EXIT_SUCCESS;
}
It calls the hooked function, but when NewExitProcess returns I get an access violation. The calls to Sleep are fine, just like any hooked function other than ExitProcess.
EDIT: I get the same issue when hooking ExitThread though.
When looking up the function declaration of ExitProcess you will find something like this:
WINBASEAPI
DECLSPEC_NORETURN
VOID
WINAPI
ExitProcess(
_In_ UINT uExitCode
);
The interesting part is DECLSPEC_NORETURN which is defined as __declspec(noreturn). It's also an attribute used by the ExitThread function that was also causing a crash for you. Looking up on the docs, we find this:
This __declspec attribute tells the compiler that a function does not return. As a consequence, the compiler knows that the code following a call to a __declspec(noreturn) function is unreachable.
According to your findings, it is not only used to disable compiler warnings, but is also used for optimization. This also explains why it would work in Debug mode.
I can't think of a good solution for this, as you are fighting the optimizer. The solution you wrote in a comment did not work for me (VS2013, Release mode, /O2). I came up with something a bit silly, but it seems to do the job for me:
int *ptr = (int*)&ExitProcess;
ptr++;
ptr--;
((VOID (WINAPI*)(UINT))ptr)(0);
In general, hooking ExitProcess of another unknown program should always exit the current thread, because it may be compiled to not have any code to return to.
I have a probelm :( i wanna make a program wich gives a random number :) i don't want use rand() function :) i wanna make one for me then turn it to a function ;) for educational purpose :)
but i have a problem :( see my code :)
#include <stdio.h>
#include <iostream>
#include <conio.h>
#include <windows.h>
#define MIN 0
#define MAX 99999
using namespace std;
typedef struct _RANDOM_INFO{
DWORD random;
DWORD min;
DWORD max;
} RANDOM_INFO, * LPRANDOM_INFO;
void Error(LPSTR lpErrorMessage){
cout << lpErrorMessage << endl;
exit(EXIT_FAILURE);
}
void GetRandom(LPVOID lpParam){
DWORD dwListSize = 10000, min = 0, max = 99999;
LPDWORD lpRandom = (LPDWORD)lpParam;
LPSTR lpFileSelf, lpKernel, lpNtdll;
HMODULE hFileSelf = NULL, hKernel = NULL, hNtdll = NULL;
hFileSelf = (HMODULE) GetModuleHandle(NULL);
hKernel = (HMODULE) GetModuleHandle("kernel.dll");
hNtdll = (HMODULE) GetModuleHandle("ntdll.dll");
lpFileSelf = (LPSTR) hFileSelf;
lpKernel = (LPSTR) hKernel;
lpNtdll = (LPSTR) hNtdll;
while(1){
DWORD i;
for(i = 0; i <= dwListSize; i++){
*lpRandom = (DWORD)lpFileSelf[i];
}
i = 0;
}
return;
}
int main(int argc, char **argv)
{
DWORD random = 0;
DWORD getRandomThreadId = 0;
HANDLE hGetRandomThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)GetRandom, &random, 0, &getRandomThreadId);
if(hGetRandomThread == INVALID_HANDLE_VALUE)
Error("Cannot make a random list.");
getch();
cout << random << endl;
Sleep(1500);
return 0;
}
The variable should get a value when and print it but i always i get 0 and a windows error can someone tell me why??? and another problem when i try to use the variable hKernel in the GetRandom function i get an error too :( but it works fine whith hFileSelf and hNtdll !!!! is kernel protected from reading???
Note : this is not a random number generation :) its just a way to get a number from the memory when the user click on the enter on his keyboard :), and its not always the same time for all users so its not always the same pointer in memory :) i hope u understand what i want do :) sorry for my bad englush :) just help me to fix the problem :)
Thank u :)
Your GetRandom() function does not have the correct signature for a CreateThread() callback procedure. Try this instead:
#include <stdio.h>
#include <iostream>
#include <conio.h>
#include <windows.h>
#define MIN 0
#define MAX 99999
using namespace std;
typedef struct _RANDOM_INFO
{
DWORD random;
DWORD min;
DWORD max;
} RANDOM_INFO, * LPRANDOM_INFO;
void Error(LPSTR lpErrorMessage)
{
cout << lpErrorMessage << endl;
exit(EXIT_FAILURE);
}
HMODULE hFileSelf = (HMODULE) GetModuleHandle(NULL);
DWORD WINAPI GetRandomThreadProc(LPVOID lpParam)
{
LPDWORD lpRandom = (LPDWORD) lpParam;
DWORD dwListSize = 10000, min = 0, max = 99999;
LPBYTE lpFileSelf = (LPBYTE) hFileSelf;
while (1)
{
for (DWORD i = 0; i <= dwListSize; ++i)
{
*lpRandom = (DWORD) lpFileSelf[i];
}
Sleep(0);
}
return 0;
}
int main(int argc, char **argv)
{
DWORD dwRandom = 0;
DWORD dwRandomThreadId = 0;
HANDLE hGetRandomThread = CreateThread(NULL, 0, &GetRandomThreadProc, &dwRandom, 0, &dwRandomThreadId);
if (hGetRandomThread == INVALID_HANDLE_VALUE)
Error("Cannot make a random list.");
do
{
getch();
cout << dwRandom << endl;
}
while (WaitForSingleObject(hGetRandomThread, 0) == WAIT_TIMEOUT);
CloseHandle(hGetRandomThread);
return 0;
}
i wanna make a program wich gives a random number
What you are doing has nothing to do with random number generation.
This is one way to do it:
Linear Congruential Generator
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;
}