1.线程概念
- 内核对象:
内核对象是由操作系统内核分配,只能由内核访问的数据结构,供系统和应用程序使用来管理各种系统资源 。 - 句柄:
创建内核对象时,函数的返回值,标记该内核对象。个人理解类似于函数指针。 - 进程:
进程就是应用程序的运行实例。进程由私有虚拟地址空间、代码、数据和其它操作系统资源(如进程创建的文件、同步对象等)组成 - 线程:
是程序执行流的最小单元,是被系统独立调度和分派的基本单位。进程是线程的执行环境,一个进程的所有线程共享它的虚拟地址空间、全局变量和操作系统资源。
2.线程库
1)C++11的Boost线程库,C++11线程的头文件是<thread>
2)pthread库,定义了创建和操纵线程的一整套API。线程的头文件是<pthread.h>
,在类unix和windows系统中都可用。
3)WIN的线程API函数,线程的头文件是 <windows.h>
本文主要记录win线程API函数。
3.多线程优缺点
- 优点:
资源利用率更好;
程序设计在某些情况下更简单;
程序响应更快; - 缺点:
增加了调度和管理的开销;
线程之间的同步和加锁控制比较麻烦;
一个线程的崩溃可能影响到整个程序的稳定性;
线程最大数有限,线程能够提高的总性能有限,而且线程多了之后,线程本身的调度也是一个麻烦事儿,需要消耗较多的CPU 。
多线程就是在一个进程内有多个线程。从而使一个应用程序有了多任务的功能。
4.多线程应用
为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而互不干扰,如当前进程要完成三件事情1、2、3,那么CPU会分别用10%的时间来同时处理这3件事情,从而让CPU的使用率达到了30%,大大地提高了CPU的利用率。
大多情况下,要用到多线程的主要是需要处理大量的IO操作时或处理的情况需要花大量的时间等等,比如:读写文件、视频图像的采集、处理、显示、保存;服务端的监听等;耗时或大量占用处理器的任务阻塞用户界面操作;各个任务必须等待外部资源(如远程文件或 INTERNET 连接)。
5.线程通信
1)线程间通信
- 1.用全局变量
主要由于多个线程可能更改全局变量,因此全局变量最好声明为violate - 2.使用消息实现通信
在Windows程序设计中,每一个线程都可以拥有自己的消息队列(UI线程默认自带消息队列和消息循环,工作线程需要手动实现消息循环),因此可以采用消息进行线程间通信sendMessage,postMessage。 - 用事件CEvent类实现线程间通信
Event对象有两种状态:有信号和无信号,线程可以监视处于有信号状态的事件,以便在适当的时候执行对事件的操作。
2)线程间同步
各个线程可以访问进程中的公共变量,资源,所以使用多线程的过程中需要注意的问题是如何防止两个或两个以上的线程同时访问同一个数据,以免破坏数据的完整性。
线程间的通信目的主要是用于线程同步。下面两种情况下,线程间需要通信: - 1)当有多个线程访问共享资源而不希望共享资源遭到破坏;(互斥)
- 2) 当一个线程需要将某个任务已经完成的情况通知另外一个或多个线程时;(同步)
Windows线程通信方法主要有互锁函数、临界区、互斥量、信号量、事件
线程间的同步方式有四种 - 临界区
临界区对应着一个CcriticalSection对象,当线程需要访问保护数据时,调用EnterCriticalSection函数;当对保护数据的操作完成之后,调用LeaveCriticalSection函数释放对临界区对象的拥有权,以使另一个线程可以夺取临界区对象并访问受保护的数据。 - 互斥量
互斥与临界区很相似,但是使用时相对复杂一些(互斥量为内核对象),不仅可以在同一应用程序的线程间实现同步,还可以在不同的进程间实现同步,从而实现资源的安全共享。 - 信号量
信号量的用法和互斥的用法很相似,不同的是它可以同一时刻允许多个线程访问同一个资源,PV操作 - 事件
事件分为手动置位事件和自动置位事件。事件Event内部它包含一个使用计数(所有内核对象都有),一个布尔值表示是手动置位事件还是自动置位事件,另一个布尔值用来表示事件有无触发。由SetEvent()来触发,由ResetEvent()来设成未触发。
6.线程示例
- 1临界区
#include<iostream>
#include<windows.h>
using namespace std;
CRITICAL_SECTION cs;
DWORD WINAPI ThreadFunc1(PVOID param)
{
for(int i=1;i<=10;i++) {
EnterCriticalSection(&cs);
cout<<"ThreadFunc1 Output:"<<i<<endl;
LeaveCriticalSection(&cs);}
return 0;
}
DWORD WINAPI ThreadFunc2(PVOID param)
{
for(int i=1;i<=10;i++) {
EnterCriticalSection(&cs);
cout<<"ThreadFunc2 Output:"<<i<<endl;
LeaveCriticalSection(&cs); }
return 0;
}
DWORD WINAPI ThreadFunc3(PVOID param)
{
for(int i=1;i<=10;i++) {
EnterCriticalSection(&cs);
cout<<"ThreadFunc3 Output:"<<i<<endl;
LeaveCriticalSection(&cs); }
return 0;
}
int main()
{
InitializeCriticalSection(&cs);
HANDLE ThreadHandle1 = CreateThread(NULL,0,ThreadFunc1,NULL,0,NULL);
HANDLE ThreadHandle2 = CreateThread(NULL,0,ThreadFunc2,NULL,0,NULL);
HANDLE ThreadHandle3 = CreateThread(NULL,0,ThreadFunc3,NULL,0,NULL);
HANDLE hThread[3] = {ThreadHandle1,ThreadHandle2,ThreadHandle3};
WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
DeleteCriticalSection(&cs);
CloseHandle(ThreadHandle1 );
CloseHandle(ThreadHandle2);
CloseHandle(ThreadHandle3);
return 0;
}
- 2互斥量
#include <iostream>
#include <windows.h>
using namespace std;
HANDLE hMutex;
DWORD WINAPI ThreadFun(LPVOID lpParamter)
{
while(1)
{
WaitForSingleObject(hMutex, INFINITE);
cout<<"Fun!"<<endl;
Sleep(500);
ReleaseMutex(hMutex);
}
}
int main()
{
HANDLE hThread = CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL);
hMutex = CreateMutex(NULL, FALSE, "screen");
while(1)
{
WaitForSingleObject(hMutex, INFINITE);
cout<<"main!"<<endl;
Sleep(500);
ReleaseMutex(hMutex);
}
CloseHandle(hThread);
CloseHandle(hMutex);
return 0;
}
- 3信号量
#include <iostream>
#include <windows.h>
using namespace std;
HANDLE hsemp1,hsemp2;
const int th_number = 2;
int i1=0,i2=0;
DWORD WINAPI ThreadFun1(LPVOID lpParameter)
{
for(int i=0;i<10;i++)
{
WaitForSingleObject(hsemp1,INFINITE);//等待信号量
cout<<"ThreadFun1->"<<i<<endl;
ReleaseSemaphore(hsemp1,1,NULL);//释放信号量
}
return 0;
}
DWORD WINAPI ThreadFun2(LPVOID lpParameter)
{
for(int i=0;i<10;i++)
{
WaitForSingleObject(hsemp2,INFINITE);//等待信号量
cout<<"ThreadFun2->"<<i<<endl;
Sleep(500);
ReleaseSemaphore(hsemp2,1,NULL);//释放信号量
}
return 0;
}
int main()
{
hsemp1 = CreateSemaphore(NULL,1,1,"screen");
hsemp2 = CreateSemaphore( NULL,1,1,"screen");
HANDLE hThread[th_number] = {0};
hThread[0] = CreateThread(NULL,0,ThreadFun1,NULL,0,NULL);
hThread[1] = CreateThread(NULL,0,ThreadFun2,NULL,0,NULL);
WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
CloseHandle( hThread[0] );
CloseHandle( hThread[1] );
CloseHandle( hsemp1 );
CloseHandle( hsemp2 );
return 0;
}
- 4事件
#include <iostream>
#include <windows.h>
using namespace std;
HANDLE evRead,evWrite;
DWORD WINAPI ReadThread(PVOID param)
{
WaitForSingleObject (evRead,INFINITE);
cout<<"Reading"<<endl;
SetEvent(evWrite);
return 0;
}
DWORD WINAPI WriteThread(PVOID param)
{
cout<<"Writing"<<endl;
SetEvent(evRead);
return 0;
}
int main()
{
evRead = CreateEvent (NULL ,FALSE ,FALSE ,NULL) ;
evWrite = CreateEvent (NULL ,FALSE ,FALSE ,NULL) ;
HANDLE th1=CreateThread(NULL,0, ReadThread,NULL,0,NULL);
HANDLE th2=CreateThread(NULL,0, WriteThread,NULL,0,NULL);
WaitForSingleObject(evWrite,INFINITE) ;
CloseHandle(evRead);
CloseHandle(evWrite );
CloseHandle(th1);
CloseHandle(th2);
return 0 ;
}