在做一个爬天气网上的多个省的天气网页,感觉单线程太慢,随用到多线程看看能优化多少。。。
首先在每次CreateThread后Sleep(1000),总共建32个线程,每个线程对应一个网页:
for(int i=0;i<32;i++) { hThread[i]=CreateThread(NULL,0,WeatherProc,p,0,&dwThreadId[i]);
Sleep(1000); }
这样会快点,但是想到一个问题,如果抓取的HTML文件还没有存储完毕,主线程就结束,在这里说一下,不管你创建的线程运行到哪,主线程不管,只要main()里的语句执行完,所有线程也就结束了。这样的话整个程序就没有什么意义。。。存取的数据不完整。
Sleep(1000)试了下会存在该种情况,换了Sleep(2000),存储完整了,但是感觉这个不是完美的解决方案。Sleep(2000)确实让线程抢占的机会多了,但是还是不能确保完整存储所有网页的信息。
后来想到一个方法就是设置标志量法了
while(1) { for( i=0;i<32;i++) { if(flag[i]==0) { Sleep(100); i=-1; } } if(i==32) break; }
在每个线程的执行函数末尾将flag数组的对应位置设置为1,表明该网页已经完整存储。只要存在任何一个网页没有存储完毕,主线程睡觉。。。。
线程这东西运用的好的话,的确很有用,但是搞不清的话,结果让人很苦恼。
已经从最初单线程十分钟减小到5秒。
linux下可以这样,让线程必须执行:
#include<stdio.h> #include<unistd.h> #include<pthread.h> void* task(void* x) { int i; for(i=0;i<10000;i++) printf("task is running\n"); pthread_exit((void*)0); } int main() { int ret=0; void *p; pthread_t pid; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);//如果第三个参数设置为PTHREAD_CRAETE_DETACHED,那就不能确定线程是否会执行 pthread_create(&pid,&attr,task,NULL); ret=pthread_join(pid,&p); printf("ret=%d,p=%d\n",ret,(int)p); //sleep(3); }
现在有C++11已经支持join这种形式了,但好多还不支持。。。
void my_thread() { puts("hello, world"); } int main(int argc, char *argv[]) { std::thread t(my_thread); t.join(); system("pause"); return 0; }
#include <iostream> #include <stdlib.h> #include <thread> #include <string> void my_thread(int num, const std::string& str) { std::cout << "num:" << num << ",name:" << str << std::endl; } int main(int argc, char *argv[]) { int num = 1234; std::string str = "tujiaw"; std::thread t(my_thread, num, str);//传参很方便了 t.detach();//设置为分离 system("pause"); return 0; }
独占式互斥量:
#include <iostream>
#include <stdlib.h>
#include <thread>
#include <string>
#include <mutex>
int g_num = 0;
std::mutex g_mutex;
void thread1()
{
//g_mutex.lock();
std::lock_guard<std::mutex> lg(g_mutex); g_num = 10;
for (int i=0; i<10; i++){
std::cout << "thread1:" << g_num << std::endl;
}
//g_mutex.unlock();
}
void thread2()
{
std::lock_guard<std::mutex> lg(g_mutex);
g_num = 20;
for (int i=0; i<10; i++){
std::cout << "thread2:" << g_num << std::endl;
}
}
int main(int argc, char *argv[])
{
std::thread t1(thread1);
std::thread t2(thread2);
t1.join();
t2.join();
system("pause");
return 0;
}
允许超时的互斥量
std::timed_mutex g_timed_mutex; void thread1() { std::unique_lock<std::timed_mutex> tl(g_timed_mutex); ::Sleep(3000); // 睡眠3秒 puts("thread1"); } void thread2() { std::unique_lock<std::timed_mutex> tl(g_timed_mutex, std::chrono::milliseconds(1000)); // 超时时间1秒 puts("thread2"); } int main(int argc, char *argv[]) { std::thread t1(thread1); ::Sleep(100); // 让线程1先启动 std::thread t2(thread2); t1.join(); t2.join(); system("pause"); return 0; }
C++11不支持的话只有这样了:
#include<windows.h> #include<stdio.h> #include<string.h> #include <stdlib.h> HANDLE h[10]; DWORD WINAPI x(LPVOID pParam) { if(pParam) { int i=*(int *)pParam; for(int j=0;j<10;j++) printf("%d\n",i); } return 1; } int main() { int i; for(i=0;i<10;i++) { int *p=new int ; *p=i; h[i]=CreateThread(NULL,0,x,(void *)p,0,NULL); ::WaitForSingleObject(h[i],INFINITE); } //for(i=0;i<10;i++) //::WaitForSingleObject(h[i],INFINITE); }
这样可以确定线程执行的顺序,也就是说线程1执行完了后线程2再执行。。。。。
如果这样:
#include<windows.h> #include<stdio.h> #include<string.h> #include <stdlib.h> HANDLE h[10]; DWORD WINAPI x(LPVOID pParam) { if(pParam) { int i=*(int *)pParam; for(int j=0;j<10;j++) printf("%d\n",i); } return 1; } int main() { int i; for(i=0;i<10;i++) { int *p=new int ; *p=i; h[i]=CreateThread(NULL,0,x,(void *)p,0,NULL); //::WaitForSingleObject(h[i],INFINITE); } for(i=0;i<10;i++) ::WaitForSingleObject(h[i],INFINITE); }
就不能保证线程执行的顺序了,但两种方法都可确定所有线程执行完毕