1、真正完成代码执行的是线程,而进程只是线程的容器,或者说是线程的执行环境。
2、当创建一个进程时,操作系统会自动创建这个进程的第一个线程,即主线程。
3、线程的组成:
1)内核对象:操作系统用它来对线程实施管理,内核对象也是系统用来存放线程统计信息的地方。
2)线程栈:它用于维护线程在执行代码时需要的所有函数参数和局部变量。
4、新线程可以访问进程的内核对象的所有句柄,进程中所有内存和在这个相同的进程中的所有其它线程的堆栈。
5、线程只有一个内核对象和一个栈,保留的记录很少,因此所需的内存也很少,由于线程需要的开销比进程少,因此在编程中经常采用多线程来解决编程问题,而尽量避免创建新的进程。而且进程间切换时,需要交换整个地址空间,而线程之间的切换只是执行环境的改变,因此效率很高。
6、线程运行,操作系统为每一个运行的线程安排一定的CPU时间——时间片。
7、static HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpsa, //指向LPSECURITY_ATTRIBUTES 结构体 的指针。
DWORD dwStackSize, //设置线程初始栈的大小
LPTHREAD_START_ROUTINE pfnThreadProc, // 指向应用程序定义的 LPTHREAD_START_ROUTINE 类型的函数的指针
void* pvParam, //上面函数命令行参数
DWORD dwCreationFlags, // 设置用于控制线程创建的附加标记, CREATE_SUSPENDED
//创建后处于暂停状态直到程序调用Resume Thread 函数为止,
//0 创建后立即运行。
DWORD* pdwThreadId ) // 这个参数是一个返回值,它指向一个变量,用来接收线程ID
8、例子:
#include <windows.h>
#include <iostream.h>
// 函数声明部分
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
);
DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
);
//全局变量
int index=0;
int tickets=100;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
// 第一个参数 NULL 说明使用默认安全性
// 第二个参数 0 让新线程采用与调用线程一样的栈大小
// 第三个参数 Fun1Proc 指定线程hThread1入口函数的地址
// 第四个参数 NULL 传递给函数的参数
// 第五个参数 0 创建后立即运行。
// 第六个参数 NULL 新线程ID,不需要,所以为NULL
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
// 关闭新线程的句柄,其实这个函数并没有中止线程,
CloseHandle(hThread1);
CloseHandle(hThread2);
//Sleep() 这个函数是使调用线程暂停自己的运行,直到指定的时间间隔过去为止,单位为毫秒。
Sleep(1000);
}
// 线程hThread1 运行的函数
DWORD WINAPI Fun1Proc(
LPVOID lpParameter // thread data
)
{
if(tickets>0)
{
cout<<"thread1 sell ticket : "<<tickets--<<endl;
}
else
break;
}
cout<<"thread1 is running"<<endl;
return 0;
}
// 线程hThread1 运行的函数
DWORD WINAPI Fun2Proc(
LPVOID lpParameter // thread data
)
{
if(tickets>0)
{
cout<<"thread2 sell ticket : "<<tickets--<<endl;
}
else
break;
}
cout<<"thread2 is running"<<endl;
return 0;
}
/***************************************************************************************************
上面程序有个致命的错误,两个线程同时使用一个全局变量,会导致变量不同步问题,如果线程1 运行到if(tickets>0) ——这时tickets == 1 ,而因为没有减1 ,刚好时间片由到了,那么就停止线程1 ,转而去运行线程2 ,这样线程2运行完时,tickets == 0,在转到线程1被暂停的地方继续去运行。这样就会出现 0 的情况。
*****************************************************************************************************/