1.       程序,进程,线程

A: 程序是计算机指令的集合,它以文件的形式存储在磁盘上,而进程通常被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动.一个程序可以对应多个进程.

进程是资源申请,高度和独立运行的单位,因此,它使用系统中的运行资源,而程序不能申请系统资源,不能被系统高度也不能作为独立运行的单位,因此它不占系统运行资源.

进程组成:

<1>   操作系统用来管理进行的内核对象

内核对象也是系统用来存放关于进程的统计信息的地方.内核对象是操作系统内部分配的一个内在块,该内存块是一种数据结构,其成员负责维护该对象的各种信息.

<2>   地址空间

它包含所有可执行模块或DLL模块的代码和数据.另外,它也包含动态内存分配的空间,例如线程的栈和堆分配空间

B: 进程从来不执行任何东西,它只是纯种的容器,若要使进行完成某项操作,它必须拥有一个在它的环境中运行的纯种,此线程负责执行包含在进程的地址空间的中的代码.也就是,真正完成代码执行的是线程,而进行只是纯种的容器,或者说是线程的执行环境.

单个进程可能包含若干个纯种,这些线程都”同时”执行进行地址空间的中代码,每个线程至少拥有一个纯种,来执行进行的地址空间中的代码,当创建一个进程时,操作系统会自动创建这个进程的第一个线程,称为主纯种.也就是执行main函数或WinMain函数的线程,可以把main函数或WinMain函数看作是主线程的入口点函数.此后,主线程可以创建其它的线程.

C: 线程也由两部分组成:

<1> 线程内核对象,操作系统用它来对线程实施管理,内核对象也是系统用来存放线程统计信息的地地方

<2>线程栈stack:它用于维护线程在执行代码时需要的所有函数参数和局部变量.线程总是在某个进程环境中创建,系统从进程的地址空间中分配内存,供线程的栈使用.

线程运行:

操作系统为每一个运行线程安排一定的CPU时间—时间片,系统通过一种循环的方式为线程提供时间片,线程在自己的时间内运行,因时间片相当短,因此给用户的感觉就是好像多个线程是同时运行一样.

2.       创建线程的SDK函数

HANDLE CreateThread (

SEC_ATTRS SecurityAttributes,//安全结构全指针,NULL为默认安全性

ULONG StackSize,//线程初始栈的大小 ,以字节为单位,如果为0或小于0,默认将使用

//与调用该线程相同的栈空间大小

SEC_THREAD_START StartFunction,//线程处理函数地址(可用函数名)

PVOID ThreadParameter,//可以为数据或其它信息的指针,表示给新线程传送参数

ULONG CreationFlags,//线程创建的标记,可以为0或CREATE_SUSPENDED,如果

//CREATE_SUSPENDED线程创建后暂停状态,直到程序调用//ResumeThread,如果为0立即运行

PULONG ThreadId //[out]返回值,系统分配新的线程ID

);

3.    一个简单的多线程程序,模拟售票系统

#include <windows.h>//必要的头文件,使用Windows API函数

#include <iostream.h>

int index = 0;

int tickets = 100;//票数

HANDLE hMutex; //使用全局的互斥对象来保证对同一资源的互斥访问与操作这里是tickets

//线程处理函数原型,形式可从MSDN中拷贝

//线程1 的入口函数

DWORD WINAPI Fun1Proc(

LPVOID lpParameter   // thread data

);

DWORD WINAPI Fun2Proc(

LPVOID lpParameter   // thread data

);

void main(){

HANDLE hThread1;

DWORD thread1ID;

//创建线程1

hThread1 = CreateThread(NULL, 0, Fun1Proc, NULL, 0, &thread1ID);

HANDLE hThread2;

DWORD thread2ID;

//创建线程2

hThread2 = CreateThread(NULL, 0, Fun2Proc, NULL, 0, &thread2ID);

CloseHandle(hThread1); //关闭线程的句柄,为什么要关闭?它将线程的使用计数减1

CloseHandle(hThread2);//这样当线程结束时,线程内核对象被释放,

//否则只有当进程结束,才释放线程的内核对象hThread1与hThread2

//创建一个互斥对象,如果成功返回互斥对象的句柄,否则返回NULL

hMutex = CreateMutex(NULL, FALSE, "tickets");

if (hMutex)

{

if(ERROR_ALREADY_EXISTS == GetLastError())

{

cout << "only one instance can run!" << endl;

return;

}

}

//      while(index++ < 100)

//      {

//                cout << "main Thread is running!" << endl;

//      }

Sleep(4000);//主线程睡眠4秒钟,给其它线程运行的时间,因为一旦主线程退出则进行退出,其它线程也将退出

}

DWORD WINAPI Fun1Proc(

LPVOID lpParameter   // thread data

){

//      while(index++ < 100)

//                cout << "Thread1 is running!" + index << endl;

while(TRUE){

WaitForSingleObject(hMutex, INFINITE);//如果全局互斥对象是有信号状态,则获得该对象,

//直到调用ReleaseMutex之前,互斥对象是无信号状态,其它线程不能对互斥对象进行访问

if(tickets > 0)

{

Sleep(1);

cout << "Thread1 sell tickets : " << tickets-- << endl;

}

else

break;

ReleaseMutex(hMutex);//将互斥对象设置为有信号状态

}

return 0;

}

DWORD WINAPI Fun2Proc(

LPVOID lpParameter   // thread data

)

{

while(TRUE){

WaitForSingleObject(hMutex, INFINITE);

if (tickets > 0)

{

Sleep(1);

cout << "Thread2 sell tickets : " << tickets-- << endl;

}

else

break;

ReleaseMutex(hMutex);

}

return 0;

}

3.       多线程聊天程序

(1)      加载套接字库在InitInstance()中,调用AfxSocketInit(),此时可以不加载库文件,但要加入Afxsock.h"头文件

if (!AfxSocketInit())

{

AfxMessageBox("加载套接字库失败!");

return FALSE;

}

(2)      在CChatDlg.h中类的声明外,创建一个全局的结构体,包含套接字和窗口的句柄值,主要是在投送消息时可以将两个需要传送的消息同时发送

struct RECVPARAM{

SOCKET socket;

HWND hWnd;

};

(3)      在CChatDlg中创建成员变量m_socket,然后增加一个成员函数,IniSocket(),在其中完成m_socket的初始化和绑定。

BOOL CChatDlg::InitSocket()

{

m_socket = socket(AF_INET, SOCK_DGRAM, 0);

if (INVALID_SOCKET == m_socket)

{

MessageBox("创建套接字失败!");

return FALSE;

}

SOCKADDR_IN addrSock;

addrSock.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

addrSock.sin_family = AF_INET;

addrSock.sin_port = htons(6010);

int bindRst;

bindRst = bind(m_socket, (SOCKADDR*)&addrSock, sizeof(SOCKADDR));

if (SOCKET_ERROR == bindRst)

{

closesocket(m_socket);

MessageBox("绑定失败!");

return FALSE;

}

return TRUE;

}

(4)      .创建一个线程,CreateThread(),须将线程函数RecvProc定义为静态的或者全局函数。因为对于运行的代码来说,它不知道要产生哪一个对象,即运行时根本不知道如何去产生一个CChatDialog类的对象,对于运行时代码来说,如果要调用纯种函数来启动某个纯种的话,应该不需要产生某个对象就可以调用这个纯种函数.因此要定义为类的静态成员或全局函数,即这个代码是所以对象共有的,不需要定义对象才能使用.

static DWORD WINAPI RecvProc(LPVOID lpParameter);

DWORD WINAPI CChatDlg::RecvProc(LPVOID lpParameter)

{

//根据线程函数参数获取发送端套接字和要设置包含文本控件的窗口句柄

SOCKET socket = ((RECVPARAM*)lpParameter)->socket;

HWND hWnd = ((RECVPARAM*)lpParameter)->hWnd;//窗口句柄

SOCKADDR_IN addrRecv;

int len = sizeof(SOCKADDR);

char recvBuf[100];

char tempBuf[100];

int recvRst;

CString recvStr;

while(TRUE)

{

//接收数据

recvRst = recvfrom(socket, recvBuf, 100, 0, (SOCKADDR*)&addrRecv, &len);

if (SOCKET_ERROR == recvRst)

{

break;

}

sprintf(tempBuf, "%s说:%s\r\n", inet_ntoa(addrRecv.sin_addr), recvBuf);

//                recvStr += tempBuf;//这种方式更加简单不用使用消息

//                ::SetDlgItemText(hWnd, IDC_EDIT_RECV, recvStr);

//使用自定义消息的方式来对控件填充内容

::PostMessage(hWnd, WM_RECVDATA, 0, (LPARAM)tempBuf);

}

return 0;

}

在OnInitDialog中调用InitSocket完成初始化工作。

InitSocket();//初始化套接字库

RECVPARAM *pRecvParm = new RECVPARAM();

pRecvParm->socket = m_socket;

pRecvParm->hWnd = m_hWnd;

HANDLE hThreadRecv = CreateThread(NULL, 0, RecvProc, (LPVOID)pRecvParm, 0, NULL);

CloseHandle(hThreadRecv);

(5)      ::PostMessage()完成将收到的数据发送给对话框。用自定义的消息参考下面的代码。注意要将EDitBox的MultiLine属性选上。

<1>:       在ChatDlg.h中#define WM_RECVDATA WM_USER+1

<2>:       afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam);

<3>:       在ChatDlg.cpp中ON_MESSAGE(WM_RECVDATA,OnRecvData)

void CChatDlg::OnRecvData(WPARAM wParam,LPARAM lParam)

{

CString str=(char*)lParam;

CString strTemp;

GetDlgItemText(IDC_EDIT_RECV,strTemp);

str+="\r\n";

str+=strTemp;

SetDlgItemText(IDC_EDIT_RECV,str);

}

(6)      最后在DWORD WINAPI CChatDlg::RecvProc(LPVOID lpParameter)

中调用 ::PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);

//不能用SendMessage()

4.对发送按纽的响应代码:

void CChatDlg::OnBtnSend()

{

// TOD Add your control notification handler code here

DWORD dwIP;

((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);

SOCKADDR_IN addrTo;

addrTo.sin_family=AF_INET;

addrTo.sin_port=htons(6000);

addrTo.sin_addr.S_un.S_addr=htonl(dwIP);

CString strSend;

GetDlgItemText(IDC_EDIT_SEND,strSend);

sendto(m_socket,strSend,strSend.GetLength()+1,0,

(SOCKADDR*)&addrTo,sizeof(SOCKADDR));

SetDlgItemText(IDC_EDIT_SEND,"");

}

VC++学习(15):多线程相关推荐

  1. VC++中多线程学习(MFC多线程)一(线程的创建、线程函数如何调用类成员呢?如何调用主对话框的成员?、MFC中的工作线程和界面线程的区别)

    这里废话不多讲了,因为项目原因,需要开启线程进行处理,在不了解线程的情况下,直接百度一下,然后就使用了,结果可想而知,出现了异常,所以花了一天时间系统学习一下多线程,这里主要是针对win32编程方面的 ...

  2. VC学习路线书籍+视频

    本人是刚刚开始学习windows编程的,感觉看雪学院的大牛很NB.想找一些书籍来看学习学习,可是不知道看哪些书好. 驱动,对菜鸟们来说真是一个很深奥的话题,所以 ,我找来了这篇文章供大家分享,以后大家 ...

  3. C#多线程学习(四) 多线程的自动管理(线程池) (转载系列)——继续搜索引擎研究...

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  4. VC学习笔记 -单选按钮控件(Ridio Button)的使用

    在VC++编程过程中,查资料是一个苦差事,案边放了一摞书左翻右翻好是烦人.一赌气就把一些常用的小技巧自己总结了一下,虽费了些功夫,但对以后编程很有好处.现拿出来与大家共享,以后积累多了,作一个CHM电 ...

  5. C#多线程学习(五) 多线程的自动管理(定时器) (转载系列)——继续搜索引擎研究...

    Timer类:设置一个定时器,定时执行用户指定的函数.               定时器启动后,系统将自动建立一个新的线程,执行用户指定的函数. 初始化一个Timer对象: Timer timer ...

  6. 学习java多线程,这必须搞懂的这几个概念

    转载自 学习java多线程,这必须搞懂的这几个概念,很重要. 同步和异步 同步,Synchronous,即调用方法开始,一旦调用就必须等待方法执行完返回才能继续下面的操作. 举个例子,你去银行ATM取 ...

  7. C#多线程学习(一) 多线程的相关概念(转自xugang的blog)

    C#多线程学习(一) 多线程的相关概念 什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源. 而一个进程又是由多个线程所组成的. 什么是线程? 线程 ...

  8. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  9. vc++学习精髓(收集,整理)

    vc++学习精髓(收集,整理) 以下是很多VC爱好者的学习经历,希望对大家有所帮助: 我记得我在网上是这么说的:先学win32的SDK,也就是API, 再学MFC,这么一来呢,就先有个基础,MFC是A ...

  10. VC学习笔记:文本图形

    VC学习笔记:文本图形  SkySeraph OCT.30th 2010  HQU Email-zgzhaobo@gmail.com  QQ-452728574 Latest Modified Dat ...

最新文章

  1. httpd服务器常见漏洞修复,网站安全监测以及漏洞修复过程
  2. Xcode10 修改代码后,编译没有反应,或者导入头文件没有提示
  3. Redis中的客户端Sharding
  4. php调整表格样式,表格的创建以及样式修改
  5. 挖掘建模-分类与预测-回归分析-逻辑回归
  6. 海洋工作室——网站建设专家:全数据库比较工具
  7. Cocos creator之javascript闭包
  8. 商品库存清单案例java_java实现超市商品库存管理平台
  9. 记录下准备蓝桥杯的过程吧
  10. vmware克隆centos修改mac地址
  11. java开发微信抢红包挂_微信抢红包算法实现(JAVA)
  12. hellow windows
  13. html div浏览器居中显示,IE浏览器DIV居中实现方法
  14. Android反编译、签名、重打包、zipalign一条龙
  15. 画质增强概述-1-定义
  16. Xcode 用Ad_Hoc方式打包
  17. AD转换中知道数字量计算模拟量或温度
  18. 瓦力机器人的配音_《机器人瓦力》的配套短片
  19. NOIP 2016 蚯蚓 题解
  20. vue使用svg的问题

热门文章

  1. Javascript-Switch
  2. windwon安装macaca环境
  3. windows下安装zabbix_agent
  4. android是32-bit系统还是64-bit系统
  5. GetModuleHandle(NULL)获取当前DLL模块基址?
  6. 判断浏览器是否为IE内核的最简单的方法
  7. DIV的边距属性在Chrome和IE中的区别
  8. Effective Objective-C 2.0 初读小结
  9. nodejs的启动方式
  10. Ajax — 评论列表