Avatar billede quiw Nybegynder
27. december 2008 - 01:16 Der er 13 kommentarer og
1 løsning

Multithreaded, string som argument.

Hejsa eksperter, nu har jeg kæmpet med at få en tråd til at starte med et argument, hvorfor vil følgende ikke fungerer?

DWORD __stdcall thread(string link){
    cout << "Du åbnede tråden med sætningen: "<<link<<"\n";
}

int main(){
  string input = "dette er en streng!";

  DWORD id;
  CreateThread(0, 0, thread, input, 0, &id);
  return 0;
}
Avatar billede bertelbrander Novice
27. december 2008 - 01:30 #1
Tråd funktionen skal tage en void* som indput. Du kan caste frem og tilbage:

DWORD __stdcall thread(void *s)
{
    cout << "Du åbnede tråden med sætningen: "<< *(string *)s <<"\n";
    return 0;
}

int main()
{
  string input = "dette er en streng!";

  DWORD id;
  CreateThread(0, 0, thread, (void *)&input, 0, &id);
  Sleep(100);
  return 0;
}

Jeg har sat en Sleep ind, ellers vil programmet (sandsynligvis) stoppe inden tråden har fået en chance for at køre.
Avatar billede arne_v Ekspert
27. december 2008 - 01:30 #2
Følgende virker hos mig:

#include <iostream>

#include <windows.h>

using namespace std;

DWORD __stdcall thread(void *p)
{
    string *link = (string *)p;
    cout << "Du åbnede tråden med sætningen: " << *link << endl;
}

int main()
{
  string input = "dette er en streng!";
  DWORD id;
  CreateThread(0, 0, thread, &input, 0, &id);
  cin.get();
  return 0;
}
Avatar billede bertelbrander Novice
27. december 2008 - 02:08 #3
Yes, jeg var 5 sekunder hurtigere end Arne ;-)
Men vi var ret enige.
Avatar billede arne_v Ekspert
27. december 2008 - 02:17 #4
Det er ikke sådan når man bliver gammel og langsom ...
Avatar billede quiw Nybegynder
27. december 2008 - 02:18 #5
Hehe :)
Men kan det passe, at mit array ikke virker således?
string input[10];
DWORD id;
CreateThread(0, 0, thread, &input[2], 0, &id2);
Avatar billede arne_v Ekspert
27. december 2008 - 02:30 #6
Følgende virker fint hos mig:

#include <iostream>

#include <windows.h>

using namespace std;

CRITICAL_SECTION cs;

DWORD __stdcall thread(void *p)
{
    string *link = (string *)p;
    EnterCriticalSection(&cs);
    cout << "Du åbnede tråden med sætningen: " << *link << endl;
    LeaveCriticalSection(&cs);
}

int main()
{
    InitializeCriticalSection(&cs);
    string input[2] = { "dette er en streng!", "dette er en anden streng!" };
    DWORD id[2];
    CreateThread(0, 0, thread, &input[0], 0, &id[0]);
    CreateThread(0, 0, thread, &input[1], 0, &id[1]);
    cin.get();
    return 0;
}
Avatar billede quiw Nybegynder
27. december 2008 - 02:36 #7
Det ser ud til at virke udmærket! Det var sidste element til at få min webcrawler til at virke:

#include <iostream>
#include <string>
#include <windows.h>
#include <cstring>

using namespace std;

CRITICAL_SECTION cs;

DWORD __stdcall crawler(void *p);

//Funktionen som henter html:
string get(char *host, char *path){
      int sock;
      int tmp;
      char *input;
      char cmd[512],resp[51200];
     
      struct sockaddr local;
      struct sockaddr remote;
      struct hostent *hostinfo;
 
      WSADATA WSAData;
      WSAStartup(0x0101,&WSAData);
     
      //Laver socket
      if((sock=socket(AF_INET,SOCK_STREAM,0))<0) {
              printf("Error\n");
      }
     
      local.sa_family = AF_INET;
      memset(local.sa_data,0,sizeof(local.sa_data));
     
      if(bind(sock,&local,sizeof(local))<0){
              printf("Error\n");                       
      }
     
      //Lookup host
      hostinfo=gethostbyname(host);
      if(!hostinfo){
              printf("Error\n"); 
      }
               
      //Connect til host:
      remote.sa_family=hostinfo->h_addrtype;
      memcpy(remote.sa_data+2,hostinfo->h_addr_list[0],hostinfo->h_length);
      *((short *)remote.sa_data)=80;
      tmp=remote.sa_data[0];
      remote.sa_data[0]=remote.sa_data[1];
      remote.sa_data[1]=tmp;
      if(connect(sock,&remote,sizeof(remote))!=0) {
              printf("Error\n");
      }
     
      //Send request:
      sprintf(cmd,"GET %s HTTP/1.1\r\nHost: %s\r\n\r\n",path,host);
      if(send(sock,cmd,strlen(cmd),0)<0) {
                    printf("Error sending GET request\n");
      }
       
      //Læs respons
      int ix=0;
      int len;
      while ((len=recv(sock,resp+ix,sizeof(resp)-ix-1,0))>0) {
            ix = ix + len;
      }
      resp[ix]='\0';
     
      //Close socket
      closesocket(sock);
      WSACleanup();
      return resp;
}

//Funktionen der finder alle links i html dokumentet
void findlink(string buffer){
    int s = 2;
    string link[1000];
   
    for (int i = 0; i!=buffer.length();i++){
        if(buffer.at(i)=='h' && buffer.at(i+1)=='r' && buffer.at(i+2)=='e' && buffer.at(i+3)=='f'){
                          for(int y = 0; y!=300; y++){
                                  if(buffer.at(i+y+6)!='"'){
                                        link[s].push_back(buffer.at(i+y+6));
                                  }else{
                                        s++;
                                        break;
                                  }
                          }
        }
    }
    for(int m = 0;m!=1000;m++){
            if(link[m]!=""){
                  cout << "#crawling link: "<<link[m] << "\n";
                  //Starter ny tråd til at crawle nyt link
                  CreateThread(0, 0, crawler, (void*)&link[m], 0, 0);
            }
    }
}

//Selve crawleren, som deler links op i host og path:
DWORD __stdcall crawler(void *p){
    string link = *(string*)p;
    EnterCriticalSection(&cs);
   
    string host;
    string path;
   
    char host2[100];
    char path2[100];
   
    int offset = strlen("http://");
   
    cout << "#Thread started\n";
    if(link.find("http")<link.length()){
          for(int i = offset; i!=link.length();i++){
                  if(link.at(i)=='/'){
                      path=link.substr(i,link.length());
                      host=link.substr(offset,i-offset);
                      break;
                  }
          }
          strcpy(host2,host.c_str());
          strcpy(path2,path.c_str());

          if(strlen(host2)<1){
              cout << "#Reached deadend\n";
          }else{
              findlink(get(host2,path2));
          }
    }
    LeaveCriticalSection(&cs);
}

int main(){
  string start = "http://www.google.com/test";
  InitializeCriticalSection(&cs);
  CreateThread(0, 0, crawler, &start, 0, 0);
  cin.get();
  return 0;
}

- Men, bertel var først med svaret, men arne havde svaret på mit yderliggående spørgsmål, i må begge ligge et svar :)

Mange tak for hjælpen :)
Avatar billede arne_v Ekspert
27. december 2008 - 03:02 #8
Et par kommentarer:

- du skal kun bruge critical section, når det er absolut nødvendigt - hvis du bruger
  det i hele din tråd metode, så fungerer den basalt set single threaded (og det var jo
  ikke meningen) - du skal kune bruge den der hvor der tilgåes shared variable - og cout
  er en shared variabel, men din hent og parse kode skulle gerne fungere på lokale
  variable det meste af tiden og har derfor ikek behov for at være i critical section
- muligvis kunne din parser blive både pænere kode blive mere robust overfor varianter
  (tænk f.eks. brug af single quites omkring attributter !) hvis du brugte regex til
  at parse med
- jeg kan ikke lide din tråd model, du starter konsekvent tråde når du finder links, hvis
  du finder mange links så starter du rigtigt mange tråde - jeg vil anbefale en fast
  antal tråde og en queue af links, fundne links smides i queue, en tråd processer et
  link og når den er færdig henter den næste link fra queue

Og et svar fra mig.
Avatar billede bertelbrander Novice
27. december 2008 - 03:09 #9
Jeg samler ikke på point.
Giv dem til ungdommen, Arne er vist et par år yngre end mig...
Avatar billede quiw Nybegynder
27. december 2008 - 12:20 #10
Jeg forsøger lige at forbedre koden, med de forslag du har givet .. Derefter poster jeg nok sourcen igen, til inspiration for andre :)
- Mange tak begge 2 :)
Avatar billede quiw Nybegynder
27. december 2008 - 16:40 #11
Jeg har nu redigeret tæmmelig meget, og er sluppet af med critical section, og min parse-kode er meget mere fleksibel og finder kun links, og med fast antaltråde som arbejder ud fra en kø:

#include <iostream>
#include <windows.h>
#include <string>


using namespace std;

// QUERY:
string global_host[100000];
string global_path[100000];

//Number of threads:
int threads = 10;
   
string get(char *host, char *path){
      int sock;
      int tmp;
      char *input;
      char cmd[512],resp[51200];
     
      struct sockaddr local;
      struct sockaddr remote;
      struct hostent *hostinfo;
 
      WSADATA WSAData;
      WSAStartup(0x0101,&WSAData);
     
      //Create socket
      if((sock=socket(AF_INET,SOCK_STREAM,0))<0) {
              printf("Error\n");
      }
     
      local.sa_family = AF_INET;
      memset(local.sa_data,0,sizeof(local.sa_data));
     
      if(bind(sock,&local,sizeof(local))<0){
              printf("Error\n");                       
      }
     
      //Lookup host
      hostinfo=gethostbyname(host);
      if(!hostinfo){
              printf("Error\n"); 
      }
               
      //Connect to host:
      remote.sa_family=hostinfo->h_addrtype;
      memcpy(remote.sa_data+2,hostinfo->h_addr_list[0],hostinfo->h_length);
      *((short *)remote.sa_data)=80;
      tmp=remote.sa_data[0];
      remote.sa_data[0]=remote.sa_data[1];
      remote.sa_data[1]=tmp;
      if(connect(sock,&remote,sizeof(remote))!=0) {
              printf("error");
      }
     
      //Send request:
      sprintf(cmd,"GET %s HTTP/1.1\r\nHost: %s\r\n\r\n",path,host);
      if(send(sock,cmd,strlen(cmd),0)<0) {
                    printf("Error sending GET request\n");
      }
       
      //Read
     
      int ix=0;
      int len;
      while ((len=recv(sock,resp+ix,sizeof(resp)-ix-1,0))>0) {
            ix = ix + len;
            if(strstr(resp,"</html>")!=NULL){
                  break;
            }
      }
      resp[ix]='\0';
      //Close socket
      closesocket(sock);
      WSACleanup();
      return resp;
}

void regex(string input){
    bool grab = false;
    int arraybuffer = 0;
    string buffer[5000];
   
    for(int i = 0; i != input.length(); i++){
            if(input.at(i)=='"'){
                  if(grab==false){
                      i++;
                      grab=true;
                  }else{
                      arraybuffer++;
                      grab=false;
                  }
            }
            if(grab==true){
                buffer[arraybuffer].push_back(input.at(i));
            }
    }
    for(int i = 0; i !=5000; i++){
            string host;
            string path;
            int offset = strlen("http://");
           
            if(buffer[i].substr(0,offset)=="http://"){
                      buffer[i]=buffer[i].substr(offset,buffer[i].length());
                      if(buffer[i].length()>1){
                          for(int y = 0; y!=buffer[i].length();y++){
                              if(buffer[i].at(y)=='/'){
                                path=buffer[i].substr(y,buffer[i].length());
                                host=buffer[i].substr(0,y);
                                cout << "host: "<<host<<"\n";
                                cout << "path: "<<path<<"\n\n";
                                for(int y = 0; y!=100000; y++){
                                        if(global_host[y].empty()){
                                              global_host[y]=host;
                                              global_path[y]=path;
                                        }
                                }
                                break;
                              }
                          }
                      }
            }
    }
}

DWORD __stdcall crawlerthread(void *p){
      char host2[500];
      char path2[500];
     
      for(int m = 0; m!=100; m++){
              for(int y = 0; y!=100000; y++){
                if(!global_host[y].empty()){
                  strcpy(host2, global_host[y].c_str());
                  strcpy(path2, global_path[y].c_str());
             
                  regex(get(host2,path2));
             
                  global_host[y].clear();
                  global_path[y].clear();
                  break;
                }
              }
      }
}
int main(){
    //Start position:
    regex(get("ekstrabladet.dk","/"));
   
    //Starting working thread:
    for(int i = 0; i!=threads;i++){
            CreateThread(0, 0, crawlerthread, (void*)1, 0, 0);
    }
   
    cin.get();
    return 0;
}
Avatar billede arne_v Ekspert
27. december 2008 - 18:38 #12
Nye kommentarer:

- det er ikke regex du bruger selvom du kalder funktionen det
- du har brug for at bruge critical section når du tilgår global_host og global_path (men kun der)
- fremfor fixed size arrays kunne du bruge queue<string> eller bare vector<string>
- fremfor 2 arrays/collections kunne du have en enkelt af en struct med 2 fields
Avatar billede quiw Nybegynder
27. december 2008 - 22:24 #13
Hm, nu har jeg fordybet mig lidt i queue, og det ser ganske smart ud, og er klart en bedre løsning. Men regex virker meget kompliceret, kan du finde et ultra simpelt eksempel som jeg kan arbejde ud fra?
Avatar billede arne_v Ekspert
28. december 2008 - 05:44 #14
Du skal have fat i et regex lib. Eller finde et regex lib i dit eksisterende environment.

Jeg plejer at bruge PCRE.

Eksempel:

#include <stdio.h>
#include <string.h>
#include <pcre.h>

typedef void (*linkhandler)(const char *, const char *);

void parse(char *html, linkhandler f)
{
    int ix;
    pcre *re;
    int rc;
    int erroffset;
    int ovector[300];
    const char *error;
    const char *url;
    const char *txt;
    re = pcre_compile("(?:<a\\s+href\\s*=\\s*[\"'])([^\"']*)(?:[\"']\\s*>)([^<]*)(?:</a>)", PCRE_CASELESS+PCRE_DOTALL+PCRE_MULTILINE, &error, &erroffset, NULL);
    rc = pcre_exec(re, NULL, html, strlen(html), 0, 0, ovector, sizeof(ovector)/sizeof(int));
    ix = 0;
    while((rc = pcre_exec(re, NULL, html, strlen(html), ix, 0, ovector, sizeof(ovector)/sizeof(int))) > 0)
    {
      pcre_get_substring(html, ovector, rc, 1, &url);
      pcre_get_substring(html, ovector, rc, 2, &txt);
      f(url, txt);
      ix = ovector[1];
    }
}

void haps(const char *url, const char* txt)
{
    printf("haps: %s / %s\n", url, txt);
}

int main()
{
    parse("bla <a href=\"foobar.html\">foobar</a> bla", haps);
    parse("bla <a href=\"foo.html\">foo</a> bla <a href=\"bar.html\">bar</a> bla", haps);
    parse("bla <a  href = 'foobar.html' >foobar</a> bla", haps);
    return 0;
}
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester