#if 0 //CreateThread代码示例 #include<iostream> #include<windows.h> using namespace std; DWORD WINAPI ThreadFun(LPVOID lpThreadParameter) { char* str = (char*)lpThreadParameter; while (true) { cout << "线程处理函数中接收到的参数是:" << str << endl; cout << "子线程ID: " << GetCurrentThreadId() << endl; Sleep(1000); } return 0; } int main() { DWORD threadId = 0; HANDLE hThread = CreateThread( NULL, //设为NULL表示默认安全性 0, //如果设为0,那么默认将使用与调用该函数的线程相同的栈空间大小 ThreadFun,//线程处理函数,函数名就是函数指针 "hello thread!",//向线程函数传入的参数 0, //0表示创建后马上运行 &threadId); if (hThread == NULL){ cout << "线程创建失败,ERROR CODE : " << GetLastError() << endl; } cout << "线程的句柄:" << hThread << endl; cout << "子线程的ID:" << threadId << endl; cout << "主线程的ID:" << GetCurrentThreadId() << endl; //关闭线程句柄,引用计数-1,并没有结束线程 //CloseHandle(hThread);//表示以后不再引用句柄 getchar(); //挂起线程 SuspendThread(hThread); getchar(); //恢复执行线程 ResumeThread(hThread); getchar(); return 0; } #endif #if 0//多线程间消息通讯 #include<iostream> #include<windows.h> #include<stdio.h> //自定义消息必须自定义在用户消息以上的数值 #define MY_MSG WM_USER+1 bool flag = true; DWORD WINAPI ThreadFun1(LPVOID param) { //接收第二个线程发来的消息 MSG msg; #if 0 //GetMessage 如果有消息继续,否则阻塞 while (GetMessage( &msg,//接收消息的线程ID NULL,//取得消息的窗口的句柄,当为NULL时获取所属线程的消息 0, //指定被检索的最小消息值的整数 0 //指定被检索的最大消息值的整数 )) { switch (msg.message){ case MY_MSG: printf("收到消息:%d\n", (int)msg.wParam); break; //case WM_QUIT: // printf("收到WM_QUIT消息,退出!\n");//因为WM_QUIT消息会让GetMessage返回false所以不会进人循环 // break; } } printf("收到WM_QUIT消息,退出!\n"); #endif #if 1 //PeekMessage的用法 不阻塞线程 while (flag) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){//得到消息返回非零,否则返回0值 switch (msg.message){ case MY_MSG: printf("收到消息:%d\n", (int)msg.wParam); break; case WM_QUIT: printf("收到QUIT消息,退出!\n"); flag = false; break; } } } #endif return 0; } DWORD WINAPI ThreadFun2(LPVOID param) { //给第一个线程发送消息 DWORD threadId = (DWORD)param; int N = 1; while (TRUE){ if (N <= 3){ PostThreadMessage(threadId, MY_MSG, (WPARAM)N++, NULL); } else{ PostThreadMessage(threadId, WM_QUIT, NULL, NULL); break; } Sleep(1000); } return 0; } int main() { DWORD threadID = 0; HANDLE hthread1 = CreateThread(NULL, 0, ThreadFun1, NULL, 0, &threadID); HANDLE hthread2 = CreateThread(NULL, 0, ThreadFun2, (LPVOID)threadID, 0, NULL); HANDLE hArr[] = { hthread1, hthread2 }; WaitForMultipleObjects(2, hArr, TRUE, INFINITE); //getchar(); system("pause"); return 0; } #endif #if 0//静态TLS(线程本地存储变量) #include<iostream> #include<Windows.h> #include<stdio.h> //声明为静态TLS(线程本地存储变量) __declspec(thread) int N = 0;//每个线程中的值互不影响 DWORD WINAPI ThreadFun1(LPVOID param){ char *name = reinterpret_cast<char *>(param);//()还不能少 while (TRUE){ printf("线程%s打印:%d\n", name, ++N); Sleep(1000); } } DWORD WINAPI ThreadFun2(LPVOID param){ char *name = reinterpret_cast<char *>(param);//()还不能少 while (TRUE){ printf("\t\t\t线程%s打印:%d\n", name, ++(++N)); Sleep(1000); } } void main(){ HANDLE hThread1 = CreateThread(NULL, 0, ThreadFun1, "thread1", 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, ThreadFun2, "thread2", 0, NULL); HANDLE hArr[] = { hThread1, hThread2 }; WaitForMultipleObjects(2, hArr, TRUE, INFINITE); system("pause"); } #endif #if 0//动态TLS(Thread Local Storage) #include<iostream> #include<stdio.h> #include<Windows.h> DWORD WINAPI ThreadFun1(LPVOID param); DWORD WINAPI THreadFun2(LPVOID param); //动态TLS的索引 DWORD tlsIndex = 0; int main() { tlsIndex = TlsAlloc();//返回索引 if (tlsIndex == TLS_OUT_OF_INDEXES){ printf("分配TLS索引失败!\n"); return 0; } //在主线程中设置一个值 TlsSetValue(tlsIndex, "main cpp"); char *pName = (char*)TlsGetValue(tlsIndex); printf("主线程打印: %s\n", pName); HANDLE hThread1 = CreateThread(NULL, 0, ThreadFun1, "A", 0, NULL); HANDLE hThread2 = CreateThread(NULL, 0, THreadFun2, "B", 0, NULL); HANDLE hArr[] = { hThread1, hThread2 }; WaitForMultipleObjects(2, hArr, TRUE, INFINITE);//等待两个线程执行完毕 TlsFree(tlsIndex); system("pause"); return 0; } DWORD WINAPI ThreadFun1(LPVOID param){ TlsSetValue(tlsIndex, "hello"); while (true) { char *p = (char*)TlsGetValue(tlsIndex); printf("线程A打印:%s\n", p); Sleep(1000); } } DWORD WINAPI THreadFun2(LPVOID param){ TlsSetValue(tlsIndex, "world"); while (true) { char *p = reinterpret_cast<char *>(TlsGetValue(tlsIndex)); printf("\t\t\t线程B打印:%s\n", p); Sleep(1000); } } #endif #if 0//利用事件Event实现买票程序 #include<iostream> #include<Windows.h> #include<stdio.h> #include<process.h>//_beginthread void __cdecl SellThread1(void* param); void __cdecl SellThread2(void* param); int tickets = 100; //个INVALID_HANDLE_VALUE ( vs2008下为0xfffffffff ) 实际值等于-1 //INVALID_HANDLE_VALUE类似与指针里的NULL,如果将指针释放后,应该立即将指针赋为NULL,否则出现野指针; //同理,句柄执行closehandle后,应该立即将句柄置为INVALID_HANDLE_VALUE,即让句柄失效。 HANDLE hEvent = INVALID_HANDLE_VALUE; int main() { //创建事件,此刻为有信号状态,自动重置信号状态,初始化为有信号状态,线程可以直接获取 hEvent = CreateEvent(NULL, FALSE, TRUE, L"事件对象"); Sleep(1000); //主线程休眠1秒后,将信号量置为无信号状态 //ResetEvent(hEvent); printf("开始卖票了!\n"); //创建两个售票线程 uintptr_t t1 = _beginthread(SellThread1, 0, "售票窗口A"); uintptr_t t2 = _beginthread(SellThread2, 0, "售票窗口B"); //无限等待两个线程全部执行完毕 HANDLE hArr[] = { (HANDLE)t1, (HANDLE)t2 }; WaitForMultipleObjects(2, hArr, TRUE, INFINITE); printf("卖票结束!\n"); system("pause"); return 0; } void __cdecl SellThread1(void* param){ char *name = reinterpret_cast<char*>(param); while (tickets > 0){ //如果事件对象为信号状态(没有线程拥有它),则线程可以获取它后继续执行 //自动重置的事件对象,调用了WaitForSingleObject函数之后,自动重置为无信号, //即其他线程不能再抢占了 WaitForSingleObject(hEvent, INFINITE); if (tickets > 0){ Sleep(10); } //让事件变成有信号状态,相当于解锁 SetEvent(hEvent); } } void __cdecl SellThread2(void* param){ char *name = reinterpret_cast<char*>(param); while (tickets > 0){ WaitForSingleObject(hEvent, INFINITE); if (tickets > 0){ Sleep(10); printf("%s卖出第%d张票!\n", name, tickets--); } SetEvent(hEvent); } } #endif #if 0//利用事件对象实现一个程序只允许运行一个进程 #include<iostream> #include<windows.h> #include<stdio.h> int main() { HANDLE hEvent = CreateEvent(NULL, FALSE, TRUE, L"事件对象"); if (GetLastError() == ERROR_ALREADY_EXISTS){ printf("程序已经运行了,退出!\n"); getchar(); CloseHandle(hEvent); return 0; } printf("程序第一次运行!\n"); getchar(); return 0; } #endif #if 0//利用semaphore实现程序只允许一个进程运行 #include<iostream> #include<Windows.h> #include<stdio.h> int main() { HANDLE hSemaphore = CreateSemaphore(NULL, 3, 3, L"停车位"); if (GetLastError() == ERROR_ALREADY_EXISTS){ printf("程序已经运行,请不要开启多个进程!\n"); getchar(); CloseHandle(hSemaphore); return 0; } printf("程序第一次运行!\n"); getchar(); CloseHandle(hSemaphore); return 0; } #endif #if 0 //采用互斥体来实现单进程运行 #include<iostream> #include<Windows.h> #include<stdio.h> int main() { HANDLE hMutex = CreateMutex(NULL, FALSE, L"售票互斥体"); if (GetLastError() == ERROR_ALREADY_EXISTS){ printf("程序已经运行,退出\n"); getchar(); CloseHandle(hMutex); return 0; } printf("第一次运行程序!\n"); getchar(); return 0; } #endif #if 0 //信号量控制停车场车位 #include<windows.h> #include<stdio.h> DWORD WINAPI ThreadFun(LPVOID param); struct Car{ char name[20]; DWORD time; }; HANDLE hSemphore = INVALID_HANDLE_VALUE; int main() { //初始化三个停车位资源 hSemphore = CreateSemaphore(NULL, 3, 3, L"停车场"); HANDLE hArr[5] = { INVALID_HANDLE_VALUE }; for (int i = 0; i < 5; ++i){ Car *pCar = new Car; sprintf_s(pCar->name, "车辆%c", 'A' + i); pCar->time = 3 + i * 3; //创建车辆线程 hArr[i] = CreateThread(NULL, 0, ThreadFun, (LPVOID)pCar, 0, NULL); } //等待所有线程执行完毕 WaitForMultipleObjects(5, hArr, true, INFINITE); return 0; } DWORD WINAPI ThreadFun(LPVOID param) { //如果有剩余车位资源(有信号状态),就放行(往下执行) WaitForSingleObject(hSemphore, INFINITE); Car *pCar = reinterpret_cast<Car*>(param); printf("%s进入停车场,停车%d秒!\n", pCar->name, pCar->time); Sleep(pCar->time * 1000); printf("%s离开停车场!\n", pCar->name); //释放一个停车位(信号量+1) ReleaseSemaphore(hSemphore, 1, NULL); return 0; } #endif #if 0//互斥体 售票 #include<iostream> #include<process.h> #include<stdio.h> #include<windows.h> void __cdecl SellThread1(void* param); void __cdecl SellThread2(void* param); int tickets = 100; HANDLE hMutex = INVALID_HANDLE_VALUE; int main() { hMutex = CreateMutex(NULL, FALSE, L"售票互斥体"); printf("开始卖票了!\n"); uintptr_t t1 = _beginthread(SellThread1, 0, "售票窗口A"); uintptr_t t2 = _beginthread(SellThread2, 0, "售票窗口B"); HANDLE hArr[] = { (HANDLE)t1, (HANDLE)t2 }; WaitForMultipleObjects(2, hArr, true, INFINITE); printf("卖票结束!\n"); system("pause"); return 0; } void __cdecl SellThread1(void* param){ char *name = reinterpret_cast<char *>(param); while (tickets > 0){ //如果这个互斥体为有信号状态(没有线程拥有它),则线程获取它后继续执行 WaitForSingleObject(hMutex, INFINITE); if (tickets > 0){ Sleep(10); //CPU恰好执行到这里,这个时候线程的时间片到了,并且此时还剩最后一张票 printf("%s卖出第%d张票!\n", name, tickets--); } //释放对互斥体的拥有权 ,它变成有信号状态 ReleaseMutex(hMutex); } } void __cdecl SellThread2(void* param){ char *name = reinterpret_cast<char *>(param); while (tickets > 0){ WaitForSingleObject(hMutex, INFINITE); if (tickets > 0){ Sleep(10); printf("%s卖出第%d张票!\n", name, tickets--); } ReleaseMutex(hMutex); } } #endif #if 0 //pv操作 生产者 消费者模式 P操作指:通过 V操作指:释放 #include<windows.h> #include<queue> #include<process.h> using namespace std; queue<int> store; int StoreSize = 3;//仓库可以放3个货物 int ID = 1;//货物起始ID //随机时间数组,模拟随机生产和消费的速度 int arr1[10] = { 2, 1, 3, 5, 9, 2, 5, 2, 3, 7 }; //需要两个Event来通知 HANDLE hEvent1 = INVALID_HANDLE_VALUE;//有货物时通知消费者去取货物 HANDLE hEvent2= INVALID_HANDLE_VALUE;//仓库有空时通知生产者开始生产 //生产者 void ProducerThread(LPVOID param); //消费者 void ConsumerThread(LPVOID param); int main() { //需要先开始生产 hEvent1 = CreateEvent(NULL, TRUE, TRUE, L"事件对象1"); //一开始,仓库没货取 hEvent2 = CreateEvent(NULL, TRUE, FALSE, L"事件对象2"); uintptr_t t1 = _beginthread(ProducerThread, 0, NULL); uintptr_t t2 = _beginthread(ConsumerThread, 0, NULL); //无限等待两个线程运行结束 HANDLE hArr[] = { (HANDLE)t1, (HANDLE)t2 }; WaitForMultipleObjects(2, hArr, TRUE, INFINITE); CloseHandle(hEvent1); CloseHandle(hEvent2); system("pause"); return 0; } //生产者 void ProducerThread(LPVOID param){ while (true) { WaitForSingleObject(hEvent1, INFINITE);//看event是否允许生产 if (store.size() < StoreSize)//仓库有空才生产 { int id = ID++; printf("生产货物:%d\n", id); store.push(id); Sleep(arr1[id % 10] * 1000); } else{//仓库满了 ResetEvent(hEvent1);//把事件设为无信号状态 printf("仓库满了!\n"); } //如果仓库有货可以通知消费者来取货物了 if (store.size() > 0){ SetEvent(hEvent2);//让消费者的事件对象有信号 } } } //消费者 void ConsumerThread(LPVOID param){ while (true) { //看event2是否允许取货物 WaitForSingleObject(hEvent2, INFINITE); if (store.size() > 0){ int id = store.front(); store.pop();//获取队列中的货物 printf("\t\t\t取出货物:%d\n", id); Sleep(arr1[(id + 3) % 10] * 1000); } else{//仓库空了 ResetEvent(hEvent2);//设为无信号,不能取货物了 printf("\t\t\t仓库空了!\n"); } if (store.size() < 3){ SetEvent(hEvent1);//通知生产者继续生产 } } } #endif //-------------------- C++11 多线程 ------------------------- #if 0//原子操作 线程并发,非原子操作错误演示 #include<iostream> #include<atomic>//原子操作头文件 #include<thread> using namespace std; enum { T=100000 }; //atomic<int> N = 0; int N = 0; void ThreadFun(){ for (int i = 0; i < T/*2*T*/; ++i){ ++N;//线程并发导致叠加操作,不是原子操作,因此肯定少于2T } } int main(){ thread t1(ThreadFun); thread t2(ThreadFun); t1.join(); t2.join(); cout << N << endl; system("pause"); } #endif #if 0//原子操作 #include<iostream> #include<atomic>//原子操作头文件 #include<thread> using namespace std; enum { T = 1000000 }; atomic<int> N = 0;//原子操作,避免多线程并发导致的叠加操作 //int N = 0; void ThreadFun(){ for (int i = 0; i < T/*2*T*/; ++i){ ++N; } } int main(){ thread t1(ThreadFun); thread t2(ThreadFun); t1.join(); t2.join(); cout << N << endl; system("pause"); } #endif #if 0//原子操作,十人赛跑 #include<iostream> #include<atomic> #include<thread> #include<vector> using namespace std; using namespace std::this_thread; atomic<bool> ready = false;//是否枪响 atomic_flag win = ATOMIC_FLAG_INIT;//终点线 void Run(int id){ //抢没响不能跑 while (!ready) { yield();//让其他线程先执行 } for (int i = 0; i < 100000000; ++i){} //如果没有设置过,返回false if (!win.test_and_set()){ cout << id << " 号选手赢得第一名!" << endl; } } int main(int id){ //十个选手赛跑 vector<thread> vecPlayer; for (int i = 0; i < 10; ++i){ vecPlayer.push_back(thread(Run, i)); } cout << "十个选手已经准备好了!" << endl; //准备发命令 //sleep_for(chrono::seconds(3)); cout << "...3..." << endl; sleep_for(chrono::seconds(1)); cout << "...2..." << endl; sleep_for(chrono::seconds(1)); cout << "...1..." << endl; //可以跑了 ready = true; //等待所有选手跑完 for (thread &t : vecPlayer){ t.join(); } system("pause"); return 0; } #endif #if 0 //C++11 互斥锁-1 #include<iostream> #include<mutex> #include<thread> #include<stdexcept> using namespace std; using namespace std::this_thread; mutex m; void ThreadFun() { try { for (int i = 0; i < 10; ++i) { sleep_for(chrono::seconds(1)); m.lock(); //lock_guard<mutex> lck(m);//哪怕发生异常也是可以安全解锁,因为lck会析构,然后解锁mutex if (i == 3) throw logic_error("发生异常了!");//发生异常后m无法解锁,线程无法结束,所以程序会锁死无法向下执行 cout << "A打印" << i << endl; m.unlock();//抛出异常时,导致没有unlock,使得B无法获取mutex, 死锁 } } catch (logic_error & e) { cout << "错误:" << e.what() << endl; } } void ThreadFun2() { for (int i = 0; i < 10; ++i) { sleep_for(chrono::seconds(1)); //lock_guard<mutex> lck(m); m.lock(); cout << "B打印" << i << endl; m.unlock(); } } int main() { thread t1(ThreadFun); thread t2(ThreadFun2); t1.join(); t2.join(); return 0; } #endif #if 0 //C++11 互斥锁-2 #include<iostream> #include<mutex> #include<thread> #include<stdexcept> using namespace std; using namespace std::this_thread; mutex m; void ThreadFun() { try { for (int i = 0; i < 10; ++i) { sleep_for(chrono::seconds(1)); //m.lock(); lock_guard<mutex> lck(m);//哪怕发生异常也是可以安全解锁,因为lck会析构,然后解锁mutex if (i == 3) throw logic_error("发生异常了!"); cout << "A打印" << i << endl; //m.unlock();//抛出异常时,导致没有unlock,使得B无法获取mutex, 死锁 } } catch (logic_error & e) { cout << "错误" <<e.what()<< endl; } } void ThreadFun2() { for (int i = 0; i < 10; ++i) { sleep_for(chrono::seconds(1)); lock_guard<mutex> lck(m); //m.lock(); cout << "B打印" << i << endl; //m.unlock(); } } int main() { thread t1(ThreadFun); thread t2(ThreadFun2); t1.join(); t2.join(); return 0; } #endif #if 0//独占锁 #include<iostream> #include<mutex> #include<thread> #include<stdexcept> using namespace std; using namespace std::this_thread; mutex m; void threadFun1(){ try{ for (int i = 0; i < 10; i++) { unique_lock<mutex> lck(m); //m.lock();// if (i == 3) throw logic_error("发生异常了!"); cout << "A 打印: " << i << endl; //m.unlock();//使用lck.lock()主动上锁,当抛出异常时,导致没有unlock,使得B无法获取mutex,死锁 //但是使用unique_lock则不会出现死锁的情况,离开作用于会自动解锁,但是也可以手动lck.unlock()来手动解锁 sleep_for(chrono::seconds(1)); } } catch (logic_error &e){ cout << "错误" << e.what() << endl; } } void threadFun2(){ for (int i = 0; i < 10; i++) { unique_lock<mutex> lok(m); cout << "打印B: " << i << endl; //lok.unlock();//可以手动解锁,也可以不用 sleep_for(chrono::seconds(1)); } } int main() { thread t1(threadFun1); thread t2(threadFun2); t1.join(); t2.join(); system("pause"); return 0; } #endif #if 0 #include<iostream> #include<mutex> #include<condition_variable> #include<thread> using namespace std; using namespace std::this_thread; using namespace std::chrono; condition_variable cv;//仅支持unique_lock<mutex>作为wait的参数 condition_variable_any cv2;//接受任何lockable参数作为wait的参数 mutex m; void ThreadFun(int id){ unique_lock<mutex> lck(m); cv.wait(lck);//等待被唤醒,否则一直卡在这里 cout << "线程ID: " << id << "执行!" << endl; } int main(){ thread t1(ThreadFun, 1); thread t2(ThreadFun, 2); thread t3(ThreadFun, 3); cout << "3秒后被唤醒" << endl; sleep_for(seconds(3));//3秒后被唤醒 //cv.notify_all();//唤醒所有线程 t1.join(); t2.join(); t3.join(); system("pause"); return 0; } #endif #if 0 //async线程异步 #include<iostream> #include<future> #include<thread> using namespace std; using namespace std::this_thread; using namespace std::chrono; int work(int a, int b) { cout << "开始计算:" << endl; sleep_for(seconds(5));//假设某个计算需要耗时5s return a + b; } int main(){ future<int> result = async(work, 123, 456);//线程同步函数 result.wait(); //等待线程结束运行 cout << "算出结果:" << endl; int sum = result.get();//获取线程返回的结果 cout << "最终的结果是: " << sum << endl; system("pause"); return 0; } #endif #if 0 #include<iostream> #include<future> #include<thread> using namespace std; using namespace std::this_thread; using namespace std::chrono; void work(promise<int> &prom){ cout << "开始计算!" << endl; sleep_for(seconds(3)); cout << "计算完成!" << endl; prom.set_value(666);//promise 设置结果值 可以被future get到 } int main() { //定义一个promise promise<int> prom; //future 和 promise 搭配使用,类似于aynsc future<int> result = prom.get_future(); thread t1(work, ref(prom)); t1.detach(); int sum = result.get(); cout << "获取结果:" << sum << endl; system("pause"); return 0; } #endif
文章来源: C++ 练习-多线程