`
kmplayer
  • 浏览: 508799 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

程序,线程和进程

阅读更多
1,程序
程序计算机指令的集合,它以文件的形式存储在磁盘上.

2,进程
进程通畅被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动.

进程由两部分组成:
(1)内核对象:操作系统用它来管理进程,也用来存放进程的统计信息.
(2)地址空间:包含所有可执行模块或DLL模块的代码和数据,还包含动态内存分配的空间,如线程堆栈和堆分配空间.

进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源.
进程是不活泼的。进程从来不执行任何东西,它只是线程的容器。若要使进程完成某项操作,它必须拥有一个在它的环境中运行的线程,此线程负责执行包含在进程的地址空间中的代码。
单个进程可能包含若干个线程,这些线程都“同时” 执行进程地址空间中的代码。
每个进程至少拥有一个线程,来执行进程的地址空间中的代码。当创建一个进程时,操作系统会自动创建这个进程的第一个线程,称为主线程。此后,该线程可以创建其他的线程.

进程地址空间:
(1)系统赋予每个进程独立的虚拟地址空间。对于32位进程来说,这个地址空间是4GB。
(2)每个进程有它自己的私有地址空间。
进程A可能有一个存放在它的地址空间中的数据结构,地址是0x12345678,而进程B则有一个完全不同的数据结构存放在它的地址空间中,地址是0x12345678。当进程A中运行的线程访问地址为0x12345678的内存时,这些线程访问的是进程A的数据结构。当进程B中运行的线程访问地址为0x12345678的内存时,这些线程访问的是进程B的数据结构。进程A中运行的线程不能访问进程B的地址空间中的数据结构,反之亦然。
(3)4GB虚拟地址空间中,2GB是内核方式分区,供内核代码、设备驱动程序、设备I/O高速缓冲、非页面内存池的分配和进程页面表等使用,而用户方式分区使用的地址空间约为2GB,这个分区是进程的私有地址空间所在的地方。一个进程不能读取、写入、或者以任何方式访问驻留在该分区中的另一个进程的数据。对于所有应用程序来说,该分区是维护进程的大部分数据的地方。

3,线程

线程由两个部分组成:
(1)线程的内核对象,操作系统用它来对线程实施管理。内核对象也是系统用来存放线程统计信息的地方。
(2)线程堆栈,它用于维护线程在执行代码时需要的所有参数和局部变量。

线程总是在某个进程环境中创建。系统从进程的地址空间中分配内存,供线程的堆栈使用。新线程运行的进程环境与创建线程的环境相同。因此,新线程可以访问进程的内核对象的所有句柄、进程中的所有内存和在这个相同的进程中的所有其他线程的堆栈。这使得单个进程中的多个线程确实能够非常容易地互相通信。

4,能使用多线程时,不用多进程的原因:
(1)每创建一个进程,系统都要为新进程分配私有地址空间,占用资源比较多.线程只有一个内核对象和一个堆栈,保留的记录很少,因此所需要的内存也很少。
(2)进程间的切换,需要交换整个地址空间.而线程间的切换只需要交换执行环境,效率高很多.

主线程和子线程抢占系统资源,输出结果.
#include <iostream>
#include <windows.h> //使用windows API函数
using namespace std;

//线程的入口函数
DWORD WINAPI Fun1Proc(
  LPVOID lpParameter
);

int index=0;
int main()
{
    HANDLE hThread1;
    //CreateThread(
    //NULL缺省安全性;
    //指定初始提交栈的大小 0:表示调用线程一样的大小;
    //线程的入口函数;
    //指定一个参数传递给进程(命令行);
	//指定线程创建的附加标记0:表示线程创建后立即运行;
	//接受线程ID标识的变量 NULL:表示不会返回)
    hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL); //	//创建一个线程 返回线程的句柄
    CloseHandle(hThread1);//关闭线程的句柄
    while(index++<1000)
        cout<<"main thread is running\n";
    return 0;
}
DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
)
{
    while(index++<1000)
        cout<<"thread1 is running\n"<<endl;
	return 0;
}


两个子线程,出售火车票.
线程函数的中间断开,导致输出结果有误.
#include <iostream>
#include <windows.h>
using namespace std;

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter
);
DWORD WINAPI Fun2Proc(
  LPVOID lpParameter
);
int index=0;
int tickets=100;
int main()
{
    HANDLE hThread1;
    HANDLE hThread2;
    hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
    hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
    CloseHandle(hThread1);//关闭线程的句柄
    CloseHandle(hThread2);

    Sleep(4000); //休息一段时间,给子线程获取资源的机会
    return 0;
}
DWORD WINAPI Fun1Proc(
  LPVOID lpParameter
)
{
	while(TRUE)
	{
		if(tickets>0)
		{
		    //这里存在问题,可能线程从这里中断,出现了tickets等于0的情况.
		    //引出下面的互斥对象,保护指定的代码段
			Sleep(1);
			cout<<"thread1 sell ticket : "<<tickets--<<"\n";
		}
		else
			break;
	}
}

DWORD WINAPI Fun2Proc(
  LPVOID lpParameter
)
{
	while(TRUE)
	{
		if(tickets>0)
		{
		    //这里存在问题,可能线程从这里中断,出现了tickets等于0的情况.
			Sleep(1);
			cout<<"thread1 sell ticket : "<<tickets--<<"\n";
		}
		else
			break;
	}
}



解决方式:保护特定的代码段.
CreateMutex():创建互斥对象.
线程WaitForSingleObject(),如果其他进程通过Release()使得互斥对象变为有信号状态,此时线程获得了互斥对象的所有权.互斥对象内部维护的ID变为该线程的ID,计数器由0变为1.
如果线程继续调用WaitForSingleObject(),那么计数器加1.Release()的结果,只是让互斥对象维护的计数器减1.
如果一个线程调用WaitForSingleObject()得到了互斥对象的所有权,却没有释放.那么当该线程终止的时候,操作系统会自动收回互斥对象所有权,使其变为有信号状态.
互斥对象变为有信号的原因,可通过WaitForSingleObject()的返回值来得到.
#include <iostream>
#include <windows.h>
using namespace std;

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter
);
DWORD WINAPI Fun2Proc(
  LPVOID lpParameter
);

int tickets=100;
HANDLE hMutex;//互斥对象句柄
int main()
{
    HANDLE hThread1;
    HANDLE hThread2;
    hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
    hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
    CloseHandle(hThread1);
    CloseHandle(hThread2);

    hMutex=CreateMutex(NULL,TRUE,NULL);//创建未命名互斥对象
    //hMutex=CreateMutex(  LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName );
	//创建互斥对象,返回一个互斥句柄
	//安全性NULL
	//BOOL调用对象是否获得互斥对象的所有权
	//lpName给互斥对象命名

	WaitForSingleObject(hMutex,INFINITE);//主线程拥有了,又申请了一次,这时计数器变为2.
	ReleaseMutex(hMutex);
	ReleaseMutex(hMutex);  //必须释放两次,这样互斥对象才处于有信号状态.
    Sleep(3000); //休息一段时间,给子线程获取资源的机会
    return 0;
}
DWORD WINAPI Fun1Proc(
  LPVOID lpParameter
)
{
	while(TRUE)
	{
	    WaitForSingleObject(hMutex,INFINITE);//请求互斥对象
		if(tickets>0)
			cout<<"thread1 sell ticket : "<<tickets--<<"\n";
		else
			break;
        ReleaseMutex(hMutex);//释放指定互斥对象的所有权
	}
	return 0;
}

DWORD WINAPI Fun2Proc(
  LPVOID lpParameter
)
{
	while(TRUE)
	{
	    WaitForSingleObject(hMutex,INFINITE);
		if(tickets>0)
			cout<<"thread2 sell ticket : "<<tickets--<<"\n";
		else
			break;
        ReleaseMutex(hMutex);
	}
	return 0;
}
分享到:
评论

相关推荐

    进程和线程之间的关系

    ### 进程和线程之间的关系 在计算机科学领域中,进程和线程是两个非常重要的概念,它们之间既有联系又有区别。对于初学者来说,理解进程与线程的关系至关重要,因为这有助于深入掌握操作系统的基本原理及应用。下面...

    线程和进程的区别.txt

    ### 线程和进程的区别 #### 进程与线程的基本概念 在现代操作系统(如Windows、UNIX等)中,进程(Process)和线程...在实际开发过程中,根据具体需求合理地利用进程和线程的概念,可以有效地优化软件的设计和实现。

    Qt线程之间通信、线程和进程之间通信实例

    在编程领域,多线程和多进程是提升应用程序性能和响应速度的重要手段。Qt库,一个跨平台的应用程序开发框架,提供了丰富的API来支持线程和进程间的通信。本实例将深入探讨Qt如何实现线程间通信以及线程与进程间通信...

    线程,进程,程序的区别

    程序、进程和线程是操作系统中的基础概念,它们在计算机科学中有不同的含义,对于理解计算机如何运行至关重要。 程序(Program)是指一组按照特定顺序排列的计算机指令的集合,目的是执行特定的任务或解决特定的...

    进程与线程的生动形象理解

    从更专业的角度出发,进程是指并发执行的程序在执行过程中分配和管理资源的基本单位,是竞用计算机系统资源的基本单位。每个进程都有自己独立的地址空间,即进程空间。进程空间的大小取决于处理机的位数。例如,16位...

    Java 的多线程,程序、进程和线程的概念31

    首先,我们来了解一下程序、进程和线程的基础概念: 1. **程序**:程序是一组有序的指令,它们定义了计算机执行特定任务的逻辑步骤。这些指令通常以源代码的形式存在于文本文件中,由编程语言编写而成。 2. **进程...

    最清楚的进程线程,进程和线程对比

    在操作系统中,进程和线程是两个非常核心的概念,它们代表了程序在系统中的运行状态以及运行方式。为了深入理解这两个概念,我们首先要明确什么是进程。 进程是具有一定独立功能的程序关于某个数据集合上的一次运行...

    内核线程和进程的区别

    内核线程和进程的区别主要体现在它们在Linux操作系统中的实现机制和运行方式。首先需要理解的是,在Linux系统中,线程被抽象...这些特点决定了内核线程特别适合执行系统管理任务,而普通进程则适用于执行用户级的程序。

    loadrunner线程和进程的区别[参考].pdf

    首先,让我们来明确进程和线程的基本概念: **进程** 是操作系统中运行的程序实例,每个进程都有自己的内存空间和系统资源,如内存地址空间、文件描述符等。进程是系统分配资源的基本单位,彼此之间相对独立,可以...

    程序,进程,线程解析

    5. 介绍进程的分叉(fork)和线程; 6. 介绍进程之间的通信:管道的概念(两个进程之间的管道通信是要经过内核的); 7. 介绍消息队列:消息队列是内核地址空间中的内部链表,通过内核在各个进程之间传递内容; 8. ...

    易语言多线程监控进程源码

    "易语言源码分享站"标签提示我们,这个压缩包可能包含了易语言编写的多线程进程监控程序的源代码。通过阅读和学习这些源代码,开发者可以了解到如何在易语言中实现多线程,以及如何获取和处理系统进程数据。content....

    python线程与进程实现方式

    总结起来,理解Python中的线程、进程和协程是进行并发编程的关键。生成器和装饰器提供了强大的工具,使我们能够以简洁的方式实现并发和异步操作。通过熟练掌握这些概念和技术,开发者可以编写出更加高效、灵活的...

    易语言多线程监控进程

    在本主题中,我们聚焦于"易语言多线程监控进程"这个技术点,将深入探讨如何使用易语言实现多线程来监控系统中的进程,并获取其状态,以及如何处理相关的操作,如进入、退出和关闭线程,以及在特定事件发生时发送邮件...

    JAVA线程与进程的区别

    进程和线程都是操作系统所体会的程序运行的基本单元,但是它们之间有着本质的区别。在 Java 语言中,线程支持与语言运行环境结合在一起,提供了多任务并发执行,这使得多线程程序的并发性变得更加高效。

    73道Java面试题合集-多线程与进程

    - **线程**:是程序执行的最小单元,共享同一进程的资源,有自己的程序计数器、栈和局部变量。 2. **线程与进程的区别**: - 进程间不共享内存,而线程间默认共享内存,通信更高效。 - 创建和销毁进程开销大,...

    进程线程及死锁

    理解进程和线程的概念对于操作系统的设计和实现至关重要。 在POSIX规范中,fork和kill是两个常用的系统调用。fork系统调用用于创建新的进程,返回值是子进程的进程ID,而kill系统调用用于终止某个进程。pthread_...

    进程和线程详解

    学习进程和线程对于理解操作系统的运行机制,优化程序性能,以及解决并发问题都具有重要意义。无论是系统管理员还是软件开发者,都需要深入了解这两个概念,以便在实践中做出正确的选择和决策。通过阅读“进程和线程...

    c语言多进程多线程编程

    在计算机科学中,多进程和多线程是两种并发执行的方式,它们允许程序在同一时间处理多个任务,从而提高系统的效率和响应性。C语言作为一门底层且强大的编程语言,提供了丰富的系统调用接口来实现多进程和多线程编程...

Global site tag (gtag.js) - Google Analytics