多线程相关的编程,有很多说法,有人说应该去除,因为他带了了潜在的安全性,但有人有建议保留,因为他充分利用了cpu,只要我们注意其中的安全问题,所以多线程可以为我们造福,所以关于多线程编程,我们应该更多注意安全性的问题!
1.创建一个线程
(1)利用CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreateionFlag,
LPDWORD lpTHreadId
)
第一个参数:在一般情况下设置为NULL
第二个参数:设置线程堆栈大小。通常设置为0,表示使用默认大小。
第三个参数:指向线程函数的指针
第四个参数:想线程函数传递的参数,是一个LPVOID指针类型。如果不需要传递参数,设置为NULL
第五个参数:创建线程标志,当为CREATE_SUSPENED时,表示创建后线程刮起(需要启动线程,调用ResumeThread()即可);当为0时,表示创建后线程立即执行。
第六个参数:保存当前新线程的ID.
(2)DWORD WaitForsingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
)
第一个参数:一个事件的句柄,在本例中是线程句柄。
第二个参数:等待时间间隔。如果永久等待,则设置为INFINITE,在本例中等待5000豪秒
此函数返回 三个值:WAIT_OBJECT_0 (核心对象已被激活),WAIT_TIMEOUT(等待超时),WAIT_FAILED(出现错误)。
(3)我们写了一个win32console的程序,见如下:
// 创建线程.cpp : #include "stdafx.h"
#include<windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI TestThreadProc(LPVOID pParam);
int main(int argc, char* argv[])
{
DWORD dwThreadId = 0;
const int nMaxCount = 100;
HANDLE hThread = CreateThread(NULL,0UL,TestThreadProc,(void*)&nMaxCount,0,&dwThreadId);
WaitForSingleObject(hThread,5000);//主线程等待5秒
CloseHandle(hThread);
return 0;
}
DWORD WINAPI TestThreadProc(LPVOID pParam)
{
const int nMax = *(int *)pParam;
for ( int i=0;i<nMax;i++)
{
cout << i<<endl;
Sleep(100);
}
return 0;
}
2.线程的挂起和唤醒
当主线程希望次工作线程暂停时,需要调用函数DWORD SuspendThread(HANDLE hThread)将此工作线程挂起。相反,当希望一个挂起的工作线程重新运行,调用函数DWORD ResumThread(HANDL hThread)将恢复线程工作。最后可以利用closeHandle(HANDLE hThread)关闭掉一个线程句柄,但并非终止。
同样也是一个win32程序,演示线程先运行5秒,然后将线程挂起,然后睡眠3秒,然后唤醒恢复线程!
// 线程的挂起与恢复.cpp :#include "stdafx.h" #include<windows.h> #include <iostream> using namespace std; DWORD WINAPI TestThreadProc(LPVOID pParam); int main(int argc, char* argv[]) { DWORD dwThreadID = 0; const int nMaxCOunt = 100; //创建线程,线程入口地址为TestThreadProc,传入参数为(void*)&nMaxCount //返回线程句柄为hThread,其创建线程的ID为dwThreadId; HANDLE hThread = CreateThread(NULL,0UL,TestThreadProc,(void*)&nMaxCOunt,0,&dwThreadID); //等待5000毫秒,如果线程退出,则返回0 if ( WAIT_OBJECT_0 == WaitForSingleObject(hThread,5000)) { return 0; } SuspendThread( hThread);//挂起线程 Sleep(3000);//睡眠3秒 ResumeThread(hThread);//唤醒线程 WaitForSingleObject(hThread,INFINITE);//一直等待线程结束为止 CloseHandle(hThread);//关闭线程句柄 return 0; } DWORD WINAPI TestThreadProc(LPVOID pParam) { const int nMax = *(int*)pParam; for (int i=0;i<nMax;i++) { cout << i <<" "<<endl; Sleep(100); //每隔100毫秒打印一次 } cout<<"线程执行完毕!"<<endl; return 0; }
3.终止一个线程
有两种,一种是非常野蛮方法,及函数BOOL TerminateThread(HANDLE hThread,DWORD wExitCode),此方法不再外不得已的情况下,不建议使用!
第二种方法,可以设置一个全局变量,也可以设置一个结束时间,当我们要结束线程时,设置为false,那么线程跳出,自动终止!
#include "stdafx.h" #include <windows.h> #include <iostream> using namespace std; DWORD WINAPI TestThreadProc(LPVOID pParam); BOOL bTerminate; int main(int argc, char* argv[]) { DWORD dwThreadId; bTerminate = FALSE; const int nMaxCnt = 100; HANDLE hThread = CreateThread(NULL, 0, TestThreadProc, (LPVOID)&nMaxCnt, CREATE_SUSPENDED, &dwThreadId); if(hThread == INVALID_HANDLE_VALUE) { return -1; } ResumeThread(hThread); if(WAIT_OBJECT_0 == WaitForSingleObject(hThread, 3000)) return -1; bTerminate = TRUE; WaitForSingleObject(hThread, INFINITE); return 0; } DWORD WINAPI TestThreadProc(LPVOID pParam) { const int nMax = *(int*)pParam; for(int i = 0; i < nMax; i++) { if(bTerminate) { cout << "收到线程终止命令!" << endl; break; } cout << "the number is " << i << endl; Sleep(100); } cout << "线程执行结束!" << endl; return 0; }
4.CEvent类的使用,待续!
5.CCriticalSection类的使用
CCritcalSection即临界区,主要用作当某个时间内只允许最多一个线程修改某些数据或其他一些资源时,比如在某个时间内只允许最多一条线程去完成,对于链表改变节点数据的操作,应该用CCriticalSection对象控制,也就是说,在某个时间点上至多只有一个线程允许在这个链表上增加,删除,修改!
本例也是Win32的一个例子。
(1)首先修改Project-Setting-General-Microsoft Fondation—该为Use MFC as Static Library
( 2 )定义一个CCriticalSection cs对象
(3)对你要保护的代码段之前套上,cs.lock() 和 cs.Unlock();
// 如何使用CCriticalSection.cpp : #include "stdafx.h" #include <afxmt.h> CCriticalSection cs; DWORD WINAPI CSTestThread1(LPVOID pParam); DWORD WINAPI CSTestThread2(LPVOID pParam); DWORD WINAPI CSTestThread3(LPVOID pParam); #include<iostream> using namespace std; int main(int argc, char* argv[]) { HANDLE hThread[3]; DWORD dwThreadId[3]; hThread[0] = CreateThread(NULL,0UL,CSTestThread1,NULL,0,&dwThreadId[0]); hThread[1] = CreateThread(NULL,0UL,CSTestThread2,NULL,0,&dwThreadId[1]); hThread[2] = CreateThread(NULL,0UL,CSTestThread3,NULL,0,&dwThreadId[2]); WaitForMultipleObjects(3,hThread,TRUE,INFINITE);//等三个线程 for ( int i=0;i<3;i++) { CloseHandle(hThread[i]); } return 0; } DWORD WINAPI CSTestThread1(LPVOID pParam) { for(int i = 0; i < 5; i++) { cs.Lock(); cout << "I am the thead one" << endl; cs.Unlock(); Sleep(2000); } return 0UL; } DWORD WINAPI CSTestThread2(LPVOID pParam) { for(int i = 0; i < 5; i++) { cs.Lock(); cout << "I am the thead two" << endl; cs.Unlock(); Sleep(2000); } return 0UL; } DWORD WINAPI CSTestThread3(LPVOID pParam) { for(int i = 0; i < 5; i++) { cs.Lock(); cout << "I am the thead three" << endl; cs.Unlock(); Sleep(2000); } return 0UL; }
6.如何使用CSemaphore类
CSemphore叫信号量,也称作信号灯。相当于一个计数器,用于限制可使用资源线程的数目。比如某一间事情,考虑到程序运行的性能问题,规定同时最多不超过6个线程完成任务,这时就需要用到信号量。信号量允许多个线程同时使用共享资源,他规定了同时访问共享资源的线程最大数目。
(1)CSemaphore(
LONG lInitialCount =1 ,
LONG lMaxCount = 1,
LPCTSTR pstrName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttributes = NULL
)
第一个参数:信号量对象的初始计数值,即颗访问线程数目的初始值,取值不得大于lMaxCount且不得小于0(可等于0);
第二个参数:信号量对象计数值的最大值,该参数决定了同一时刻可访问由信号量保护的资源线程最大数目。
(2)DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
hHandle [in]对象句柄。可以指定一系列的对象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。 当等待仍在挂起状态时,句柄被关闭,那么函数行为是未定义的。该句柄必须具有 SYNCHRONIZE 访问权限。 dwMilliseconds [in]定时时间间隔,单位为milliseconds(毫秒).如果指定一个非零值,函数处于等待状态直到hHandle 标记的对象被触发,或者时间到了。
如果dwMilliseconds 为0,对象没有被触发信号,函数不会进入一个等待状态,
它总是立即返回。如果dwMilliseconds 为INFINITE,对象被触发信号后,函数才会返回。
(3)ReleaseSemaphore(
semaphore->m_hObject,1,NULL) 信号量减少计数1
运用 CSemaphore类,限制可使用资源线程的数目
运用WatiForSingleObject(),等待一个内核对象
运用ReleaseSemaphore()函数是计数器减1
代码如下:
// 如何使用CSemaphore类.cpp : #include "stdafx.h" #include<afxmt.h> //包含CSemaphore类头文件 CSemaphore *m_pSemaphore; //声明Csemaphore类指针变量,信号量 CCriticalSection cs; //声明CCriticalSection对象,控制共享资源 DWORD WINAPI SemapTestThread1(LPVOID pParam);//声明线程1 DWORD WINAPI SemapTestThread2(LPVOID pParam);//声明线程2 DWORD WINAPI SemapTestThread3(LPVOID pParam);//声明线程3 #include <iostream> using namespace std; int main(int argc, char* argv[]) { HANDLE hTread[3]; DWORD dwThreadId[3]; m_pSemaphore = new CSemaphore(2,2); hTread[0] = CreateThread(NULL,0UL,SemapTestThread1,NULL,0,&dwThreadId[0]); hTread[1] = CreateThread(NULL,0UL,SemapTestThread2,NULL,0,&dwThreadId[1]); hTread[2] = CreateThread(NULL,0UL,SemapTestThread3,NULL,0,&dwThreadId[2]); WaitForMultipleObjects(3,hTread,TRUE,INFINITE); for ( int i= 0;i< 3; i++) { CloseHandle(hTread[i]); } return 0; } DWORD WINAPI SemapTestThread1(LPVOID pParam) { WaitForSingleObject(m_pSemaphore->m_hObject,INFINITE); cs.Lock(); cout<<"I am the thread one" <<endl; cs.Unlock(); Sleep(3000); ReleaseSemaphore(m_pSemaphore->m_hObject,1,NULL); return 0UL; } DWORD WINAPI SemapTestThread2(LPVOID pParam) { WaitForSingleObject(m_pSemaphore->m_hObject, INFINITE); cs.Lock(); cout << "I am the thread two" << endl; cs.Unlock(); Sleep(3000); ReleaseSemaphore(m_pSemaphore->m_hObject, 1, NULL); return 0UL; } DWORD WINAPI SemapTestThread3(LPVOID pParam) { WaitForSingleObject(m_pSemaphore->m_hObject, INFINITE); cs.Lock(); cout << "I am the thread three" << endl; cs.Unlock(); Sleep(3000); ReleaseSemaphore(m_pSemaphore->m_hObject, 1, NULL); return 0UL; }
7.如何使用CSingleLock类
CSingleLock类通常被作为等待和释放的同步对象。所谓同步对象就是指上面几个实例讲解的CSemaphore,CMutex,CCriticalSection和CEvent。本实例以CSingleLock操作CSemaphore对象为例。
其实这个类,有点像考察官,就是你传给它一个考察的对象,如果该信号有了,那么他就来告诉你,Ok,你可以做事情了!
(1)CSingleLock(
CSynCObject* pObject,
BOOL bInitialLock = FALSE
)
第一个参数:需要等待或释放的同步对象指针
第二个参数:同步对象的初始状态。
(2)CSingleLock:Lock(
DWORD dwTimeOUt = INFINITE //等待同步对象有信号的最多时间,单位毫秒
)
#include "stdafx.h" #include <iostream> using namespace std; DWORD WINAPI UseSingleLockThread(LPVOID pParam); CSemaphore m_Semaphore(2,2); //信号灯 CEvent m_Event(FALSE,FALSE);//事件 CCriticalSection cs; //临界区保护 int main(int argc, char* argv[]) { int i; HANDLE hThread[9]; DWORD dwThreadId; for( i = 0; i < 9; i++) { m_Event.ResetEvent(); //设置事件为无信号 hThread[i] = CreateThread(NULL, 0, UseSingleLockThread, (LPVOID)&i, CREATE_SUSPENDED, &dwThreadId); ResumeThread(hThread[i]);//唤醒线程 CSingleLock lock(&m_Event); lock.Lock();//等待事件对象,如果没有消息,则一直等待 } WaitForMultipleObjects(9, hThread, TRUE, INFINITE);//同时等待9个对象 for( i = 0; i < 9; i++) { CloseHandle(hThread[i]); } return 0; } DWORD WINAPI UseSingleLockThread(LPVOID pParam) { int i = *(int*)pParam; //得到创建线程传出的参数 m_Event.SetEvent(); //设置时间对象为有 信号状态 CSingleLock lock(&m_Semaphore); lock.Lock();//等待事件 cs.Lock();//进入临界区 cout << "I am the thread " << i << endl; cs.Unlock();//离开临街区 Sleep(2000);//挂起线程2秒 return 0UL; }
8.如何使用CMutex
CMutex即互斥量。互斥量对象与临界区对象很相似,互斥对象和临界对象区都可以用于各个线程间。当然,在这种情况下使用临界区会更节省系统资源,而且更有效率。但是互斥对象可以在进程间使用,而临界区对象只能在同一进程的各线程间使用。
本例程序建立一个名为Mutex_1的互斥量对象和一个初始无信号的时间对象。然后互斥量进入进程互斥,建立一个线程且该线程的作用是20秒后设置时间为m_Event事件,直到有信号为止。编译该程序,开启两个exe,我们可以ikan到,最先开启的进程会打印两行文字,而第二个进程只打印一行,要等待20秒后才打印出第二行文字,这说明CMutex可以在进程间使用。
#include "stdafx.h" #include <afxmt.h> char szMutexText[] = "Mutex_1"; CMutex m_Mutex(FALSE, szMutexText); DWORD WINAPI UnlockMutex(LPVOID pParam); CEvent m_Event(FALSE, FALSE); #include <iostream> using namespace std; int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { cout << "程序进入MAIN函数." << endl; m_Mutex.Lock(); cout << "程序过入互斥量." << endl; m_Event.ResetEvent(); HANDLE hThread = CreateThread(NULL, 0, UnlockMutex, NULL, 0, NULL); WaitForSingleObject(m_Event.m_hObject, INFINITE); m_Mutex.Unlock(); return 0; } DWORD WINAPI UnlockMutex(LPVOID pParam) { Sleep(20000); m_Event.SetEvent(); return 0UL; }
9.线程的消息队列
本例通过线程消息队列介绍线程消息的一些知识,主要PostThreadMessage()向线程发送信息,然后使用GetMessage()获取并解析。
(1)BOOL GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax)
参数解析:
lpMsg:指向MSG结构的指针,该结构从线程的消息队列里接收消息信息。
hWnd:取得其消息的窗口的句柄。这是一个有特殊含义的值(NULL)。GetMessage为任何属于调用线程的窗口检索消息,线程消息通过PostThreadMessage寄送给调用线程。
wMsgFilterMin:指定被检索的最小消息值的整数。
wMsgFilterMax:指定被检索的最大消息值的整数。
返回值:除消息WM_QUIT外返回非0,否则返回0
(2)BOOL PostThreadMessage(
DWORD idThread,
UINT Msg,
WPARAM wParam,
LPARAM IParam);
参数:
第一个:其消息将被寄送的线程的ID,如果该线程没有消息队列,此函数将调用失败。
第二个:指定将被寄送的消息类型
第三个:附加消息
第四个:附加消息
返回值:如果调用成功返回TRUE,否则返回FALSE.
实现步骤
(1)首先为DLg类添加两个变量:
HANDLE m_hThread; DWORD m_dwThreadId;
(2)然后在OnInitDlg函数中实现如下:
BOOL CMyDlg::OnInitDialog() { m_hThread = CreateThread(NULL, 0UL, TestMessageThread, NULL, CREATE_SUSPENDED, &m_dwThreadId); if(m_hThread == INVALID_HANDLE_VALUE) { AfxMessageBox("创建线程失败!"); return TRUE; } ResumeThread(m_hThread); return TRUE; // return TRUE unless you set the focus to a control }
(3)然后我们定义几个消息,在Dlg.cpp的顶部
#define WM_USERMESSAGE1 WM_USER + 0x100 //第一个消息 #define WM_USERMESSAGE2 WM_USER + 0x106 //第二个消息 #define WM_USERMESSAGE3 WM_USER + 0x109 //第三个消息 DWORD WINAPI TestMessageThread(LPVOID pParam); //线程
(4)线程的实现函数:
DWORD WINAPI TestMessageThread(LPVOID pParam) { MSG msg; CString strText; while(GetMessage(&msg, NULL, 0U, 0U)) { switch(msg.message) { case WM_USERMESSAGE1: { char *p = (char*)msg.lParam; if(p != NULL) { strText.Format("收到Button1的消息为:\"%s\"", p); delete p; AfxMessageBox(strText); } } break; case WM_USERMESSAGE2: { int *pn = (int*)msg.lParam; if(pn != NULL) { strText.Format("收到Button2的整型数:%d", *pn); delete pn; AfxMessageBox(strText); } } break; case WM_USERMESSAGE3: { double *pd = (double*)msg.lParam; if(pd != NULL) { strText.Format("收到Button3的双精度浮点数:%lf", *pd); delete pd; AfxMessageBox(strText); } break; } default: break; } DispatchMessage(&msg); TranslateMessage(&msg); } return 0UL; }
(5)为各个button控件添加响应函数,发送不同的消息:
void CMyDlg::OnButton1() { //向线程传入消息和参数 char *p = new char[MAX_PATH]; strcpy(p, "这是第一个按钮参入的字符串消息!"); PostThreadMessage(m_dwThreadId, WM_USERMESSAGE1, NULL, (LPARAM)p); } void CMyDlg::OnButton2() { int *n = new int; *n = 200; PostThreadMessage(m_dwThreadId, WM_USERMESSAGE2, NULL, (LPARAM)n); } void CMyDlg::OnButton3() { double *fl = new double; *fl = 3.1415926; PostThreadMessage(m_dwThreadId, WM_USERMESSAGE3, NULL, (LPARAM)fl); }
实力:生产者-消费者。
#include <iostream> #include <windows.h> #include <stdlib.h> #include <ctime> using namespace std; #define BUFFER_SIZE 5 typedef int buffer_item; buffer_item buffer[BUFFER_SIZE]; int number; int in=0; int out=0; buffer_item total=0; HANDLE Mutex = CreateMutex(NULL,FALSE,NULL); //Win32 API中的Mutex Lock 用于各个生产者、消费者间的互斥 HANDLE mutex = CreateSemaphore(NULL,1,1,NULL);//Win32 API中的Semaphore 用于各个生产者、消费者间的互斥 HANDLE empty = CreateSemaphore(NULL,BUFFER_SIZE,BUFFER_SIZE,NULL);//Win32 API中的Semaphore 用于同步缓冲区满 HANDLE full = CreateSemaphore(NULL,0,BUFFER_SIZE,NULL);//Win32 API中的Semaphore 用于同步缓冲区空 int insert_item(buffer_item item) { if( (total == BUFFER_SIZE) && (number==0)) //如果采用Mutex方法且插入时发现缓冲区满,就丢弃此item { return 1; } buffer[in] = item; in = (in + 1) % BUFFER_SIZE; total++; return 0; } int remove_item(buffer_item *item) { if ( (total == 0) && (number==0)) //如果采用Mutex方法且插入时发现缓冲区空,就忽略此次remove请求 { return 1; } *item = buffer[out]; buffer[out]=0; out = (out + 1) % BUFFER_SIZE; total--; return 0; } DWORD WINAPI producer (LPVOID Prama) //生产者进程的入口函数 { buffer_item produce_item; int sleeptime; int index; DWORD producer_ID = *(DWORD*) Prama; while (TRUE) { sleeptime= 1000+ rand()%2000; Sleep(sleeptime); produce_item = 1+rand()%9; //生产者经过随机时间产生一个随机的item if(number==0) //Mutex方法 { WaitForSingleObject(Mutex,INFINITE); } else //Semaphore方法 { WaitForSingleObject(empty,INFINITE); //WaitForSingleObject(mutex,INFINITE); WaitForSingleObject(Mutex,INFINITE); } if (insert_item(produce_item)) //输出插入信息 { cout<<"Producer "<<producer_ID<<" produced item "<<produce_item<<" but full!"; for (index=0;index<BUFFER_SIZE;index++) { cout<<" "<<buffer[index]; } cout<<endl; } else { cout<<"Producer "<<producer_ID<<" produced item "<<produce_item<<" insert OK!"; for (index=0;index<BUFFER_SIZE;index++) { cout<<" "<<buffer[index]; } cout<<endl; } if(number==0) //Mutex方法解锁 { ReleaseMutex(Mutex); } else //Semaphore方法解锁 { //ReleaseSemaphore(mutex,1,NULL); ReleaseMutex(Mutex); ReleaseSemaphore(full,1,NULL); } } return 0; } DWORD WINAPI consumer(LPVOID Prama) //消费者进程的入口函数 { buffer_item consumer_item; int sleeptime; int index; DWORD consumer_ID = *(DWORD*) Prama; while (TRUE) { sleeptime= 1000+ rand()%3000; Sleep(sleeptime); //消费者经过随机时间后请求消费 if(number==0) //Mutex方法 { WaitForSingleObject(Mutex,INFINITE); } else //Semaphore方法 { WaitForSingleObject(full,INFINITE); //WaitForSingleObject(mutex,INFINITE); WaitForSingleObject(Mutex,INFINITE); } if (remove_item(&consumer_item)) //输出移除后的信息 { cout<<"Consumer "<<consumer_ID<<" wants consume but empty!"; for (index=0;index<BUFFER_SIZE;index++) { cout<<" "<<buffer[index]; } cout<<endl; } else { cout<<"Consumer "<<consumer_ID<<" wants consume remove "<<consumer_item<<" OK!"; for (index=0;index<BUFFER_SIZE;index++) { cout<<" "<<buffer[index]; } cout<<endl; } if(number==0) //Mutex方法解锁 { ReleaseMutex(Mutex); } else //Semaphore方法解锁 { //ReleaseSemaphore(mutex,1,NULL); ReleaseMutex(Mutex); ReleaseSemaphore(empty,1,NULL); } } return 0; } int main() { srand( (unsigned)time(0) ); int numProducers; //生产者数目 int numConsumers; //消费者数目 cout<<"Opearting System Experiment: Producer & Consumer."<<endl; cout<<"Realizing with Win32 API"<<endl; cout<<"0 Mutex , 1 Semaphore(others to end): "; cin>>number; if (number!=0 && number!=1) {return 0;} if (number==0) { cout<<"****************************Mutex Approach****************************"<<endl; } else cout<<"****************************Semaphore Approach****************************"<<endl; cout<<"Buffer Init: "; for (int i=0; i<BUFFER_SIZE; i++) { buffer[i]=0; cout<<"\t"<<buffer[i]; } cout<<endl; cout<<"Input the number of Producers: "; cin>>numProducers; cout<<"Input the number of Consumers "; cin>>numConsumers; HANDLE* Producers=new HANDLE[numProducers]; HANDLE* Consumers=new HANDLE[numConsumers]; for (DWORD j=0; j<numProducers; j++) { Producers[j]=CreateThread(NULL,0,producer,&j,0,NULL); //生成生产者进程,传递进程函数 } for (DWORD k=0; k<numConsumers; k++) { Producers[k]=CreateThread(NULL,0,consumer,&k,0,NULL); //生成消费者进程,传递进程函数 } Sleep(8000); return 0; }
这样我们就创建了一个线程,不断的接收我们发送的各种消息!
相关推荐
Java多线程编程实战指南(核心篇) 高清pdf带目录 随着现代处理器的生产工艺从提升处理器主频频率转向多核化,即在一块芯片上集成多个处理器内核(Core),多核处理器(Multicore Processor)离我们越来越近了――如今...
本书是一本通俗易懂的C#多线程编程指南,通过70多个容易理解的示例,循序渐进地讲解C#5.0中的异步及并发编程,引导读者了解Windows下C#多线程编程的多样性。 通过阅读本书,你将学到: 使用原始线程、异步线程,...
多线程编程 完美介绍多线程想过技术 进程和线程都是操作系统的概念。进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而...
vc多线程编程简单介绍vc多线程编程简单介绍vc多线程编程简单介绍
Windows多线程编程Windows多线程编程Windows多线程编程Windows多线程编程Windows多线程编程Windows多线程编程Windows多线程编程
C#多线程编程实例实战.doc
MFC多线程编程 MFC多线程编程 MFC多线程编程
但是对于要在最短的时间内迅速掌握多线程编程,相关的书籍是很难提供办到的,因此则需要一个实用而系统的教程。本视频教程就是要完成这个目标,看完这个系列的视频教程后,大家就可以熟练地完成本讲座的综合题,...
本书通过众多实例介绍了如何实现Windows下的多线程编程,既重点介绍了Win32API下的多线程编程和MFC下的多线程编程,又介绍了多线程机制在网络编程、图形编程和数据库中的应用。本书每一章都从简单的多线程实例出发...
C#多线程编程实例实战.pdf
linux多线程编程.pdf
SUN多线程编程指南(PDF文档 中文版) 《多线程编程指南》介绍了SolarisTM 操作系统(Solaris Operating System, Solaris OS)中 POSIX®线程和Solaris 线程的多线程编程接口。本指南将指导应用程序程序员如何创建新...
《C++面向对象多线程编程》共分13章,全面讲解构建多线程架构与增量多线程编程技术。第1章介绍了用于构建面向对象程序的不同类型C++组件,以及如何使用这些组件来构建多线程架构。第2、3、4章简要介绍进程、线程、多...
C++多线程的十个例子,学习window下多线程编程
Linux系统下的多线程编程入门.pdf Linux系统下的多线程编程入门.pdf Linux系统下的多线程编程入门.pdf Linux系统下的多线程编程入门.pdf Linux系统下的多线程编程入门.pdf Linux系统下的多线程编程入门.pdf Linux...
《Java多线程编程核心技术》建议猿友们读两遍,因为其写得没有那么抽象,第一遍有些概念不是很理解,可以先跳过并记录起来,第一遍阅读的目的主要是了解整个架构。第二遍再慢慢品味,并贯穿全部是指点来思考,并将...
多线程编程指南多线程编程指南多线程编程指南多线程编程指南
JAVA多线程编程技术PDF,是最经典的那个版本,多线程的所有知识点完爆读者
Java 高并发编程相关知识, 接下来将阅读该书, 并且进行比较详细的总结, 好记性不如烂笔头, 加油。 Java 多线程编程实战指南。
Linux下的多线程编程.pdf