-
January 28th, 2013, 04:06 AM
#1
C Windows winapi + multi-threading (HANDLE)_beginthreadex fail
This code ruined all my day. Basically I have a list of 50 webservers I administrate, I want to check them if up/alive (isAlive() function), I parse my webservers.txt file with the 50 ips/hostnames and for fastness I try to use threads (10, 20 or 30 doesn't matter) then my compiled code seems only duplicate threads with the last line in my file.
Code:
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <winsock.h>
#include <process.h>
#include <string.h>
#pragma comment(lib, "wsock32.lib")
unsigned int _stdcall isAlive(void *ptr)
{
struct sockaddr_in blah;
struct hostent *he;
WSADATA wsaData;
int i;
WORD wVersionRequested;
SOCKET sock;
char* addr = (char*)ptr;
char buff[1024];
char *ex;
ex="GET /alive.php HTTP/1.0\n\n";
char *fmsg="ALIVE";
wVersionRequested = MAKEWORD(1, 1);
if (WSAStartup(wVersionRequested , &wsaData)){
printf("Winsock Initialization failed.\n");
return(1);
}
if ((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET){
printf("Can not create socket.\n");
return(1);
}
sock = socket(AF_INET,SOCK_STREAM,0);
blah.sin_family = AF_INET;
blah.sin_port = htons(80);
blah.sin_addr.s_addr = inet_addr(addr);
if ((he=gethostbyname(addr))!=NULL){
memcpy((char *)&blah.sin_addr.s_addr,he->h_addr,he->h_length);
}
else{
if((blah.sin_addr.s_addr=inet_addr(addr))==-1){
WSACleanup();
return(1);
}
}
if (connect(sock,(struct sockaddr*)&blah,sizeof(blah))==0){
send(sock,ex,strlen(ex),0);
recv(sock,buff,sizeof(buff),0);
if(strstr(buff,fmsg)!=NULL){
printf("ALIVE: %s\n", addr);
}
}
closesocket(sock);
WSACleanup();
_endthreadex(0);
return(1);
}
int main(int argc,char *argv[])
{
if(argc!=2){
printf("Usage: %s <webservers list>\n", argv[0]);
return(1);
}
char *inname = argv[1];
FILE *infile;
char line_buffer[BUFSIZ];
char line_number;
infile = fopen(inname, "r");
if (!infile) {
printf("Couldn't open file %s for reading.\n", inname);
return 0;
}
line_number = 0;
HANDLE hThreadArray[200];
while (fgets(line_buffer, sizeof(line_buffer), infile)) {
unsigned threadID;
hThreadArray[line_number] = (HANDLE)_beginthreadex(0, 0, isAlive, line_buffer, 0, &threadID);
++line_number;
}
WaitForMultipleObjects(line_number, hThreadArray, TRUE, INFINITE);
fclose(infile);
return 0;
}
hosts.txt (11 lines in it)
myhost.com
mysecondhost.com
...
mylasthost.com
result:
C:\Documents and Settings\Xtmtrx\Desktop\Code>checkalive.exe hosts.txt
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
ALIVE: mylasthost.com
-
January 28th, 2013, 04:45 AM
#2
Re: C Windows winapi + multi-threading (HANDLE)_beginthreadex fail
Originally Posted by exitthematrix
Code:
char line_buffer[BUFSIZ];
char line_number;
/* ... */
line_number = 0;
HANDLE hThreadArray[200];
while (fgets(line_buffer, sizeof(line_buffer), infile)) {
unsigned threadID;
hThreadArray[line_number] = (HANDLE)_beginthreadex(0, 0, isAlive, line_buffer, 0, &threadID);
++line_number;
}
WaitForMultipleObjects(line_number, hThreadArray, TRUE, INFINITE);
fclose(infile);
return 0;
}
You are passing a pointer to the 'line_buffer' to each thread. However, you don't know when that thread will start. You may well have overwritten the contents of the buffer with the next line before the thread starts.
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
-
January 28th, 2013, 04:48 AM
#3
Re: C Windows winapi + multi-threading (HANDLE)_beginthreadex fail
An how should I safely start every thread with different lines read from my file? Because if I just do "printf("%s", line_buffer)" that works.
-
January 28th, 2013, 06:13 AM
#4
Re: C Windows winapi + multi-threading (HANDLE)_beginthreadex fail
Originally Posted by exitthematrix
An how should I safely start every thread with different lines read from my file? Because if I just do "printf("%s", line_buffer)" that works.
What do you mean with "that works"? Doing a single run and looking at the results does not tell you much in a multi-threaded world.
You should use a different buffer for each thread. That way you don't need to perform any synchronization. Seems the easiest for the use case you described.
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
-
January 28th, 2013, 06:20 AM
#5
Re: C Windows winapi + multi-threading (HANDLE)_beginthreadex fail
Originally Posted by D_Drmmr
What do you mean with "that works"? Doing a single run and looking at the results does not tell you much in a multi-threaded world.
You should use a different buffer for each thread. That way you don't need to perform any synchronization. Seems the easiest for the use case you described.
By "that works" I mean using "printf("%s", line_buffer)" that prints out every line out from my text.
-
January 28th, 2013, 09:11 AM
#6
Re: C Windows winapi + multi-threading (HANDLE)_beginthreadex fail
as suggested by D_Drmmr, a minimal code change would be
Code:
char line_buffer[200][BUFSIZ];
char line_number;
/* ... */
line_number = 0;
HANDLE hThreadArray[200];
while (fgets(line_buffer[line_number], sizeof(line_buffer[line_number]), infile)) {
unsigned threadID;
hThreadArray[line_number] = (HANDLE)_beginthreadex(0, 0, isAlive, line_buffer[line_number], 0, &threadID);
++line_number;
}
WaitForMultipleObjects(line_number, hThreadArray, TRUE, INFINITE);
// ...
( ignoring issues like possible buffer overruns, unchecked retun codes, etc ... )
alternatively, you could just pass the file path and a liner number to each thread, that in turn will open its own file stream seeking to the appropriate line.
Last edited by superbonzo; January 28th, 2013 at 09:13 AM.
-
January 28th, 2013, 09:14 AM
#7
Re: C Windows winapi + multi-threading (HANDLE)_beginthreadex fail
Originally Posted by exitthematrix
By "that works" I mean using "printf("%s", line_buffer)" that prints out every line out from my text.
There's little point in being vague if you want to get help. At the very least, you could post the code.
What you have now is a race condition, because you are writing (in the main thread) to the same memory you are reading from in the worker threads. That means that the results could be different on each run of your program.
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
-
January 28th, 2013, 09:13 AM
#8
Re: C Windows winapi + multi-threading (HANDLE)_beginthreadex fail
Thanks!
I did it like this:
Code:
HANDLE hThreadArray[200];
char str[MAX];
char *x[MAX];
int i = 0;
while(!feof(infile)) {
while(fgets(str, sizeof str, infile)) {
unsigned threadID;
x[i] = strdup(str);
//printf("%s", str);
//printf("%s", *(x+i));
hThreadArray[i] = (HANDLE)_beginthreadex(0, 0, isAlive, *(x+i), 0, &threadID);
i++;
}
}
WaitForMultipleObjects(i, hThreadArray, TRUE, INFINITE);
-
January 28th, 2013, 09:21 AM
#9
Re: C Windows winapi + multi-threading (HANDLE)_beginthreadex fail
This is my finished code, I added timeout also but seems to hang connected if no response back, otherwise works:
Code:
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <winsock.h>
#include <process.h>
#include <string.h>
#pragma comment(lib, "wsock32.lib")
#define MAX 10000
unsigned int _stdcall isAlive(void *ptr)
{
struct sockaddr_in blah;
struct hostent *he;
WSADATA wsaData;
int i;
WORD wVersionRequested;
SOCKET sock;
char* addr = (char*)ptr;
char buff[1024];
char *request;
request="GET /alive.php HTTP/1.0\n\n";
char *fmsg="ALIVE";
wVersionRequested = MAKEWORD(1, 1);
if (WSAStartup(wVersionRequested , &wsaData)){
printf("Winsock Initialization failed.\n");
return(1);
}
if ((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET){
printf("Can not create socket.\n");
return(1);
}
sock = socket(AF_INET,SOCK_STREAM,0);
blah.sin_family = AF_INET;
blah.sin_port = htons(80);
blah.sin_addr.s_addr = inet_addr(addr);
if ((he=gethostbyname(addr))!=NULL){
memcpy((char *)&blah.sin_addr.s_addr,he->h_addr,he->h_length);
}
else{
if((blah.sin_addr.s_addr=inet_addr(addr))==-1){
WSACleanup();
return(1);
}
}
if (connect(sock,(struct sockaddr*)&blah,sizeof(blah))==0){
send(sock,request,strlen(request),0);
recv(sock,buff,sizeof(buff),0);
if(strstr(buff,fmsg)!=NULL){
printf("ALIVE: %s", addr);
}
}
closesocket(sock);
WSACleanup();
_endthreadex(0);
return(1);
}
int main(int argc,char *argv[])
{
if(argc!=2){
printf("Usage: %s <webservers list>\n", argv[0]);
return(1);
}
char *inname = argv[1];
FILE *infile;
char line_buffer[BUFSIZ];
char line_number;
infile = fopen(inname, "r");
if (!infile) {
printf("Couldn't open file %s for reading.\n", inname);
return 0;
}
HANDLE hThreadArray[200];
char str[MAX];
char *x[MAX];
int i = 0;
while(!feof(infile)) {
while(fgets(str, sizeof str, infile)) {
unsigned threadID;
x[i] = strdup(str);
//printf("%s", *(x+i)); // DEBUG
hThreadArray[i] = (HANDLE)_beginthreadex(0, 0, isAlive, *(x+i), 0, &threadID);
i++;
}
}
WaitForMultipleObjects(i, hThreadArray, TRUE, INFINITE);
fclose(infile);
return 0;
}
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|