Hey, I'm Trying to make a programa in C++ that generate triangle, square and sine, waves. I enter the frequence, amplitude, etc, and it calculates the average of the wave. And i cah choose what wave generate by selecting a radio button.
This is a real-time system, so, if a wave is being plotted and if I choose a radio buton correspondent to another type of wave, it shall change in real time.
The error is this:
[C++ Error] FormularioPrincipal.cpp(171): E2297 'this' can only be used within a member function
It happens on the line that I'm creating the thread. Can someone help me?
Thanks!
//---------------------------------------------------------------------------
#include <vcl.h>
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <limits>
#include <complex>
#include <math.h>
#pragma hdrstop
#include "FormularioPrincipal.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
HANDLE thread1;
HANDLE thread2;
HANDLE thread3;
HANDLE thread4;
HANDLE thread5;
HANDLE Mutex;
int pipe[2];
double freq;
double per;
double freqAngular;
double pi;
double taxaAmostragem;
double tempofinal;
double deslocamento;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
DWORD WINAPI geraSinalSenoide(void *parametro){
TForm1 *FormularioPrincipal = (TForm1*) parametro;
int i;
double valorGerado;
per = StrToFloat(FormularioPrincipal->Edit2->Text);
freq = 1/per;
FormularioPrincipal->Edit3->Text = freq;
pi = 3.141592654;
taxaAmostragem = 20;
tempofinal = 1000;
freqAngular = (2 * pi)/per;
double amp = StrToFloat(FormularioPrincipal->Edit1->Text);
while(true){
for (double time=0; time<=freq; time = time + (1 / taxaAmostragem)){
WaitForSingleObject(Mutex, INFINITE);
ReleaseMutex(Mutex);
deslocamento = ( sin(freqAngular * time) * amp);
write(pipe[1], &deslocamento, sizeof(int));
FormularioPrincipal->Series1->AddXY(per, deslocamento, "", clRed);
per = per + StrToFloat(FormularioPrincipal->Edit2->Text);
//FormularioPrincipal->Label7->Caption = time;
}
Sleep(1000);
return 0;
}
};
DWORD WINAPI geraSinalQuadrado(void *parametro){
TForm1 *FormularioPrincipal = (TForm1*) parametro;
int i;
int x=0;
float valorGerado;
double per = StrToFloat(FormularioPrincipal->Edit6->Text);
freq = 1/per;
FormularioPrincipal->Edit2->Text = freq;
while(true){
for(i=0; i<freq;i++){
WaitForSingleObject(Mutex, INFINITE);
ReleaseMutex(Mutex);
valorGerado = rand() % (FormularioPrincipal->Edit1->Text);
write(pipe[1], &valorGerado, sizeof(int));
FormularioPrincipal->Series1->AddXY(per, valorGerado, "", clRed);
per = per + StrToFloat(FormularioPrincipal->Edit6->Text);
FormularioPrincipal->Series1->AddXY(per, valorGerado, "", clRed);
} Sleep(1000);
}
}
DWORD WINAPI geraSinalTriangular(void *parametro){
TForm1 *FormularioPrincipal = (TForm1*) parametro;
int i;
int x=0;
float valorGerado;
double per = StrToFloat(FormularioPrincipal->Edit6->Text);
freq = 1/per;
FormularioPrincipal->Edit2->Text = freq;
while(true){
for(i=0; i<freq;i++){
WaitForSingleObject(Mutex, INFINITE);
ReleaseMutex(Mutex);
valorGerado = rand() % (FormularioPrincipal->Edit1->Text);
write(pipe[1], &valorGerado, sizeof(int));
FormularioPrincipal->Series1->AddXY(per, valorGerado, "", clRed);
per = per + StrToFloat(FormularioPrincipal->Edit6->Text);
} Sleep(1000);
}
};
DWORD WINAPI processaNumeros(void *parametros){
TForm1* FormularioPrincipal = (TForm1*) parametros;
int dados[10];
int qtdDadosLidosBuffer=0;
float media = 0;
float soma =0;
float dif= 0;
while(true){
soma = 0;
dif = 0;
int i;
for(i=0; i<10; i++)//ele vai pegar de 10 em 10 numeros e calcular a media
{
int qtdBytesLidos;
//ler os dados do pipe
qtdBytesLidos = read(pipe[0], &dados[i], sizeof(int));
if (qtdBytesLidos == 0)
break;
}
qtdDadosLidosBuffer = i-1;
ReleaseMutex(Mutex);
for(int i=0; i<qtdDadosLidosBuffer;i++){
soma += dados[i];
}
if(qtdDadosLidosBuffer != 0)
soma/=qtdDadosLidosBuffer;//calcula a media
for(int i=0; i<qtdDadosLidosBuffer;i++){
dif = dados[i] - soma;
dif+=dif;
}
FormularioPrincipal->Edit4->Text = soma;
FormularioPrincipal->Edit5->Text = dif;
FormularioPrincipal->Edit6->Text = sqrt(dif);
Sleep(1000);//tbm espera 1 segundo
}
};
DWORD WINAPI main(void *parametro){
Mutex = CreateMutex(NULL, false, NULL);
TForm1 *FormularioPrincipal = (TForm1*) parametro;
DWORD prioridade;
prioridade = THREAD_PRIORITY_NORMAL;
if((FormularioPrincipal->RadioButton1->Checked == true) && (FormularioPrincipal->RadioButton2->Checked == false) && (FormularioPrincipal->RadioButton3->Checked == false)){
DWORD thread1ID;
thread1 = CreateThread(NULL, 0, geraSinalSenoide, this, CREATE_SUSPENDED, &thread1ID);
DWORD thread4ID;
thread4 = CreateThread(NULL, 0, processaNumeros, this, CREATE_SUSPENDED, &thread4ID);
GetExitCodeThread(thread2, &exitCode);
TerminateThread(thread2, exitCode);
GetExitCodeThread(thread3, &exitCode);
TerminateThread(thread3, exitCode);
SetThreadPriority(&thread1ID, prioridade);
}
else if((FormularioPrincipal->RadioButton1->Checked == false) && (FormularioPrincipal->RadioButton2->Checked == true) && (FormularioPrincipal->RadioButton3->Checked == false)){
DWORD thread2ID;
thread2 = CreateThread(NULL, 0, geraSinalTriangular, this, CREATE_SUSPENDED, &thread2ID);
DWORD thread4ID;
thread4 = CreateThread(NULL, 0, processaNumeros, this, CREATE_SUSPENDED, &thread4ID);
GetExitCodeThread(thread1, &exitCode);
TerminateThread(thread1, exitCode);
GetExitCodeThread(thread3, &exitCode);
TerminateThread(thread3, exitCode);
SetThreadPriority(&thread2ID, prioridade);
}
else{
DWORD thread3ID;
thread3 = CreateThread(NULL, 0, geraSinalQuadrado, this, CREATE_SUSPENDED, &thread3ID);
DWORD thread4ID;
thread4 = CreateThread(NULL, 0, processaNumeros, this, CREATE_SUSPENDED, &thread4ID);
GetExitCodeThread(thread1, &exitCode);
TerminateThread(thread1, exitCode);
GetExitCodeThread(thread2, &exitCode);
TerminateThread(thread2, exitCode);
SetThreadPriority(&thread3ID, prioridade);
}
if(_pipe(pipe, sizeof(int)*500, O_BINARY) == -1){//cria o pipe
MessageBox(NULL, "Erro ao criar pipe", "Aviso", 0);
return;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
DWORD prioridade;
prioridade = THREAD_PRIORITY_NORMAL;
DWORD thread5ID;
thread5 = CreateThread(NULL, 0, main, this, CREATE_SUSPENDED, &thread5ID);
SetThreadPriority(&thread5ID, prioridade);
ResumeThread(thread1);
ResumeThread(thread2);
ResumeThread(thread3);
ResumeThread(thread4);
ResumeThread(thread5);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
unsigned long exitCode;
GetExitCodeThread(thread1, &exitCode);
TerminateThread(thread1, exitCode);
GetExitCodeThread(thread2, &exitCode);
TerminateThread(thread2, exitCode);
GetExitCodeThread(thread3, &exitCode);
TerminateThread(thread3, exitCode);
GetExitCodeThread(thread4, &exitCode);
TerminateThread(thread4, exitCode);
GetExitCodeThread(thread5, &exitCode);
TerminateThread(thread5, exitCode);
}
//---------------------------------------------------------------------------
In DWORD WINAPI main(void *parametro) pass parametro instead of this to CreateThread since (like the error says) you're in free function and not in a member function.
Related
I'm just beginning with directx/directinput development and I'm running some tests with some code samples I've found online. Anyway, I want to hook an application that uses dinput8 to send my own custom input to the forewindow and I'm working with this base to do it:
// dllmain.cpp : Defines the entry point for the DLL application.
#define _CRT_SECURE_NO_WARNINGS // ignore some warnings...
#define _CRT_NON_CONFORMING_SWPRINTFS // ...
#include "stdio.h"
#include <windows.h>
#include "detours.h"
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <time.h>
#include "dinput.h"
#pragma comment(lib, "detours.lib")
#pragma comment(lib, "user32.lib")
typedef HRESULT(__stdcall* GetDeviceState_t)(LPDIRECTINPUTDEVICE, DWORD, LPVOID *);
HRESULT __stdcall hkGetDeviceState(LPDIRECTINPUTDEVICE pDevice, DWORD cbData, LPVOID *lpvData);
DWORD Base = 0;
DWORD GetDeviceStateOffset = 0x7670; // This is the offset of GetDeviceState from DInput8.dll
// Open IDA and Import the DInput8.dll, then look in the Functions Table for DirectInput8Create
// There is an Address (1000XXXX or 0CXXXXX) - copy it and save it for later
// Then take a look for CDIDev_GetDeviceState and copy that address too
// Now substract the Address from CDIDev_GetDeviceState from DIrectInput8Create and u'll get your offset
HANDLE tmpHandle = NULL;
HMODULE hModDInput8 = NULL;
DWORD dwGetDeviceState = NULL;
FARPROC dwDirectInput8Create = NULL;
struct MyKeys
{
BYTE Key;
DWORD StartTime;
DWORD TTL;
BOOLEAN isDown;
};
MyKeys KeyBuffer[256];
DWORD WINAPI HookThread();
void add_log(char* format, ...);
void SendKeyDInput(byte DIK_, DWORD time);
GetDeviceState_t pGetDeviceState;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
add_log("==========LOG START==========");
add_log("DLL Attached");
add_log("Creating Thread...");
tmpHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&HookThread, 0, 0, 0);
if (!tmpHandle)
{
add_log("ThreadCreation Failed!");
}
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
DWORD WINAPI HookThread()
{
Base = (DWORD)GetModuleHandleA("test.exe");
add_log("Thread Created");
add_log("game.exe Base: %x", Base);
while (!hModDInput8)
{
add_log("Searching dinput8.dll...");
hModDInput8 = GetModuleHandle(L"dinput8.dll");
Sleep(100);
}
add_log("Found dinput8.dll: %x !", hModDInput8);
while (!dwDirectInput8Create)
{
add_log("Searching GetDeviceState...");
dwDirectInput8Create = GetProcAddress(hModDInput8, "DirectInput8Create");
Sleep(100);
}
add_log("Found DirectInput8Create: %x !", dwDirectInput8Create);
dwGetDeviceState = (DWORD)((DWORD)dwDirectInput8Create - GetDeviceStateOffset);
add_log("GetDevicestate is here (DirectInput8Create - %x): %x", GetDeviceStateOffset, dwGetDeviceState);
add_log("Hooking GetDeviceState...");
pGetDeviceState = (GetDeviceState_t)DetourAttach(&(PVOID&)dwGetDeviceState, (PBYTE)hkGetDeviceState);
add_log("Initiate Keyboard Buffer...");
//initiate buffer
for (int i = 0; i < 256; i++)
{
KeyBuffer[i].isDown = false;
KeyBuffer[i].Key = 0;
KeyBuffer[i].StartTime = 0;
KeyBuffer[i].TTL = 0;
}
add_log("Going into Main Loop...");
while (true)
{
if (GetAsyncKeyState(VK_F5) & 1 << 15)
{
// We check the Most Sigificant Bit from VK_F5 (F5) whilst we shifted it with 15 bits to left 1
// and then a small delay so we have enaught time to release the key
add_log("F5 pushed attempting to sendkey");
// Sleep a short time so we have time to release the F5 Key
Sleep(500);
// Now we send a A Key with 1 sec time to our Game
SendKeyDInput(DIK_A, 1000);
}
}
return 0;
}
void SendKeyDInput(byte DIK, DWORD time)
{
KeyBuffer[DIK].Key = DIK;
KeyBuffer[DIK].TTL = time;
KeyBuffer[DIK].StartTime = GetTickCount();
}
HRESULT __stdcall hkGetDeviceState(LPDIRECTINPUTDEVICE lpDevice, DWORD cbData, LPVOID *lpvData)
{
HRESULT hResult = DI_OK;
static BYTE buffer[256];
int key_count = 0;
for (int i = 0; i<256; i++)
{
if (KeyBuffer[i].Key != 0 && KeyBuffer[i].TTL>0 && KeyBuffer[i].StartTime != 0)
{
if (GetTickCount() > KeyBuffer[i].StartTime + KeyBuffer[i].TTL && KeyBuffer[i].isDown)
{
KeyBuffer[i].Key = 0;
KeyBuffer[i].StartTime = 0;
KeyBuffer[i].TTL = 0;
KeyBuffer[i].isDown = false;
buffer[KeyBuffer[i].Key] = 0;
}
else {
KeyBuffer[i].isDown = true;
buffer[KeyBuffer[i].Key] = 0x80;
key_count += 1;
add_log("Sending Key %x for %i milliseconds count: %i", KeyBuffer[i].Key, KeyBuffer[i].TTL, key_count);
}
}
}
if (key_count != 0)
{
cbData = 256;
memcpy(lpvData, buffer, cbData);
}
else {
hResult = pGetDeviceState(lpDevice, cbData, lpvData);
}
return hResult;
}
//Creates a Logfile in the Game Directory
void add_log(char* format, ...)
{
HANDLE filehandle;
DWORD dwReadBytes;
char buffer[2048];
char writebuffer[2048];
va_list args;
va_start(args, format);
vsprintf_s(buffer, format, args);
filehandle = CreateFile(L"Log.txt", GENERIC_WRITE, 0, 0, OPEN_ALWAYS, 0, 0);
SetFilePointer(filehandle, 0, 0, FILE_END);
sprintf_s(writebuffer, 2048, "Log Added: %s\r\n", buffer);
WriteFile(filehandle, writebuffer, strlen(writebuffer), &dwReadBytes, 0);
CloseHandle(filehandle);
}
The only issue in this code is when I attempt to send input, it doesn't go through. I've gotten some help and narrowed down a solution to this, which was: "Try GetDeviceState hk just memset(buffer, 0, size) or SendDeviceData". I've searched around a bit and I've been unable to find more on how to implement this solution and I'm stumped.
Could one of you kind people show me how I could use this information to fix this base? I'd be extremely grateful, thanks.
I modified the "Using Condition Variables" example in MSDN. I created several threads, which have their own producer/consumer separately.
But the program will often hang when attached to debugger. It always hangs at SleepConditionVariableCS. When I break all and continue in debugger, the program will continue to run. I found that WakeAllConditionVariable didn't wake up some thread calls SleepConditionVariableCS, for the Ptr in PExecutingTask->BufferNotFull or PExecutingTask->BufferNotEmpty was already 0x00000000(I thought that means the condition variable is wakened).
When not attached to debugger, the program will not hang.
Has anyone encountered this problem before? How to solve it?
Here is the code:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#define BUFFER_SIZE 100
DWORD WINAPI ProducerThreadProc (PVOID p);
DWORD WINAPI ConsumerThreadProc (PVOID p);
class ExecutingTask
{
public:
void Initialize()
{
InitializeConditionVariable (&BufferNotEmpty);
InitializeConditionVariable (&BufferNotFull);
InitializeCriticalSection (&BufferLock);
QueueSize = 0;
StopRequested = FALSE;
hProducer = CreateThread(NULL, 0, ProducerThreadProc, (PVOID)this, 0, NULL);
for (int i = 0; i < 20; i++)
{
PhConsumers[i] = CreateThread (NULL, 0, ConsumerThreadProc, (PVOID)this, 0, NULL);
}
}
void Stop()
{
EnterCriticalSection (&BufferLock);
StopRequested = TRUE;
LeaveCriticalSection (&BufferLock);
WakeAllConditionVariable (&BufferNotFull);
WakeAllConditionVariable (&BufferNotEmpty);
WaitForSingleObject(hProducer, INFINITE);
WaitForMultipleObjects(20, (HANDLE *)&PhConsumers, true, INFINITE);
CloseHandle(hProducer);
for (unsigned int i = 0; i < 20; i++)
{
CloseHandle(PhConsumers[i]);
}
}
public:
ULONG QueueSize;
CONDITION_VARIABLE BufferNotEmpty;
CONDITION_VARIABLE BufferNotFull;
CRITICAL_SECTION BufferLock;
BOOL StopRequested;
HANDLE PhConsumers[20];
HANDLE hProducer;
};
DWORD WINAPI ProducerThreadProc (PVOID p)
{
ExecutingTask* PExecutingTask = (ExecutingTask*)p;
while (true)
{
EnterCriticalSection (&PExecutingTask->BufferLock);
while (PExecutingTask->QueueSize >= BUFFER_SIZE && PExecutingTask->StopRequested == FALSE)
{
// Buffer is full - sleep so consumers can get items.
SleepConditionVariableCS (&PExecutingTask->BufferNotFull, &PExecutingTask->BufferLock, INFINITE);
}
if (PExecutingTask->StopRequested == TRUE)
{
LeaveCriticalSection (&PExecutingTask->BufferLock);
break;
}
// Produce an item.
PExecutingTask->QueueSize++;
LeaveCriticalSection (&PExecutingTask->BufferLock);
WakeConditionVariable (&PExecutingTask->BufferNotEmpty);
}
return 0;
}
DWORD WINAPI ConsumerThreadProc (PVOID p)
{
ExecutingTask* PExecutingTask = (ExecutingTask*)p;
while (true)
{
EnterCriticalSection (&PExecutingTask->BufferLock);
while (PExecutingTask->QueueSize == 0 && PExecutingTask->StopRequested == FALSE)
{
// Buffer is empty - sleep so producers can create items.
SleepConditionVariableCS (&PExecutingTask->BufferNotEmpty, &PExecutingTask->BufferLock, INFINITE);
}
if (PExecutingTask->StopRequested == TRUE)
{
LeaveCriticalSection (&PExecutingTask->BufferLock);
break;
}
// Consume an item.
PExecutingTask->QueueSize--;
LeaveCriticalSection (&PExecutingTask->BufferLock);
WakeConditionVariable (&PExecutingTask->BufferNotFull);
}
return 0;
}
DWORD WINAPI ThreadProc (PVOID p)
{
ExecutingTask task;
task.Initialize();
Sleep(1000);
task.Stop();
printf ("%u exit\n", &task);
return 0;
};
int main ( void )
{
HANDLE hTaskThreads[50];
for (int i = 0; i < 50; i++)
{
hTaskThreads[i] = CreateThread (NULL, 0, ThreadProc, NULL, 0, NULL);
}
WaitForMultipleObjects(50, hTaskThreads, true, INFINITE);
for (int i = 0; i < 50; i++)
{
CloseHandle(hTaskThreads[i]);
}
}
This is a followup to this question:
I guess I don't understand the Interlocked Acquire / Release APIs. I put together the small program below. As I understand it, g_val_1, g_val_2 and g_val_3 should always be updated in the same order and should end up as all the same value. But they do not (for more than one thread).
What am I missing? Thanks.
#include "windows.h"
#include "stdio.h"
#define _THREADS_ 100
#define _TICKS_ 1000
int volatile g_threads = 0;
DWORD volatile g_val_1 = 0;
DWORD volatile g_val_2 = 0;
DWORD volatile g_val_3 = 0;
BOOL g_running = TRUE;
DWORD TestThread(PVOID ignore)
{
while (g_running)
{
InterlockedIncrementAcquire(&g_val_1);
g_val_2++;
InterlockedIncrementRelease(&g_val_3);
}
InterlockedDecrement(&g_threads);
return(0);
}
int __cdecl main(int argc, char* argv[])
{
int th, duration;
int success;
DWORD ticks;
duration = _TICKS_;
g_threads = _THREADS_;
printf("Max=%d Threads=%d Entries=%d\n", duration, g_threads);
printf("Creating Threads\n");
th = g_threads;
while (th-- > 0)
{
CreateThread(NULL,
0,
TestThread,
NULL,
NORMAL_PRIORITY_CLASS,
NULL);
}
printf("Starting Threads\n");
ticks = GetTickCount();
while ((GetTickCount() - ticks) < duration);
g_running = FALSE;
while (g_threads > 0);
ticks = GetTickCount() - ticks;
success = ((g_val_1 == g_val_2) && (g_val_1 == g_val_2));
printf("Duration=%d g_val_1=%d g_val_2=%d g_val_3=%d OK=%d\n", ticks, g_val_1, g_val_2, g_val_3, success);
}
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;
}
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.