[cpp]view plain copy
/*
每一个程序相当于一个进程,而一个进程之中可以有多个线程
*/
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<process.h> //进程函数
void run(void *p)
{
int *temp = (int *)p;
char ch[50];
sprintf(ch, "线程%d启动", *temp);
MessageBoxA(0, ch, "多线程", 0);
}
void main()
{
for (int i = 0; i < 5; i++)
{
//第一个参数为函数的地址,第二个参数为栈的大小,0代表默认大小,第三个参数为函数的实参,必须为void*类型
_beginthread(run, 0, &i); //多线程调用函数
Sleep(1000);
}
system("pause");
}
运行结果:开启五个线程!
2 阻塞式进程
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<process.h>
void changeCMDtitle(void *p)
{
int i = 1;
char str[20];
while (1)
{
Sleep(1000);
sprintf(str, "title 程序运行的第%d秒", i);
system(str);
i++;
}
}
void endMultiThread(void *p)
{
int *px = (int *)p; //指针转换
int i = 0;
while (1)
{
if (i > 5)
{
printf("%d %d ", i, *px);
_endthread(); //结束线程,该程序执行完毕之后退出,如果是return的话,直接退出
}
Sleep(1000);
i++;
}
}
void main()
{
_beginthread(changeCMDtitle, 0, NULL);
for (int i = 0; i < 5; i++)
{
HANDLE hd = _beginthread(endMultiThread, 0, &i); //hd相当于线程编号
//没有等待的情况下为多线程,五个线程同时进行
WaitForSingleObject(hd, INFINITE); //等待模式,第二个参数代表无限期等待,for循环里边相当于单线程
Sleep(1000); //有Sleep的情况下每隔一秒endMultiThread函数相继关闭,否则,同时关闭
}
system("pause");
}
运行结果:WaitForSingleObject为阻塞式进程,当且仅当当前进程执行完毕之后才会进入下一进程,否则,无限等待。
3 进程和线程之间的区别和联系
线程,在网络或多用户环境下,一个服务器通常需要接收大量且不确定数量用户的并发请求,为每一个请求都创建一个进程显然是行不通的,——无论是从系统资源开销方面或是响应用户请求的效率方面来看。因此,操作系统中线程的概念便被引进了。线程,是进程的一部分,一个没有线程的进程可以被看作是单线程的。线程有时又被称为轻权进程或轻量级进程,也是 CPU 调度的一个基本单位。
进程的执行过程是线状的,尽管中间会发生中断或暂停,但该进程所拥有的资源只为该线状执行过程服务。一旦发生进程上下文切换,这些资源都是要被保护起来的。这是进程宏观上的执行过程。而进程又可有单线程进程与多线程进程两种。我们知道,进程有 一个进程控制块 PCB ,相关程序段 和 该程序段对其进行操作的数据结构集 这三部分,单线程进程的执行过程在宏观上是线性的,微观上也只有单一的执行过程;而多线程进程在宏观上的执行过程同样为线性的,但微观上却可以有多个执行操作(线程),如不同代码片段以及相关的数据结构集。线程的改变只代表了 CPU 执行过程的改变,而没有发生进程所拥有的资源变化。出了 CPU 之外,计算机内的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。与进程控制表和 PCB 相似,每个线程也有自己的线程控制表 TCB ,而这个 TCB 中所保存的线程状态信息则要比 PCB 表少得多,这些信息主要是相关指针用堆栈(系统栈和用户栈),寄存器中的状态数据。进程拥有一个完整的虚拟地址空间,不依赖于线程而独立存在;反之,线程是进程的一部分,没有自己的地址空间,与进程内的其他线程一起共享分配给该进程的所有资源。
线程可以有效地提高系统的执行效率,但并不是在所有计算机系统中都是适用的,如某些很少做进程调度和切换的实时系统。使用线程的好处是有多个任务需要处理机处理时,减少处理机的切换时间;而且,线程的创建和结束所需要的系统开销也比进程的创建和结束要小得多。最适用使用线程的系统是多处理机系统和网络系统或分布式系统。
线程只有 3 个基本状态:就绪,执行,阻塞。
线程存在 5 种基本操作来切换线程的状态:派生,阻塞,激活,调度,结束。
2. 进程通信。
单机系统中进程通信有 4 种形式:主从式,会话式,消息或邮箱机制,共享存储区方式。
主从式典型例子:终端控制进程和终端进程。
会话式典型例子:用户进程与磁盘管理进程之间的通信。
4 进程和线程之间的区别和联系(二)
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
2.关系
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
3.区别
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
2) 线程的划分尺度小于进程,使得多线程程序的并发性高。
3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
4) 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
4.优缺点
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。
5 多线程程序设计的八个规则
6 多线程编程实例:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<process.h>
int flag = 1; //标志位,便于各进程之间进行通信
int *destPtr = NULL; //所查找元素的目标地址,设置为NULL是为了避免野指针
struct MultiSearch{
int len; //要查找的长度
int data; //要查找的数据
int *beg; //要查找的起始地址
int *sflag; //标志位,便于各进程之间进行通信
int **addr; //产地一个指针的地址
int index; //进程编号
};
void find(void *ptr)
{
struct MultiSearch *pstruct = (struct MultiSearch *)ptr;
for (int *pbeg = pstruct->beg; pbeg != pstruct->beg + pstruct->len; pbeg++)
{
Sleep(30); //留出一些时间,让其他线程查找
if (*(pstruct->sflag) == 0) //判断是否找到,如果找到,则终止程序
{
printf("本线程%d无能,其他线程已经找到。 ", pstruct->index);
return; //结束该线程,本线程以后的程序不再执行
}
if (pstruct->data == *pbeg) //判断该元素是否和查找的元素相等,如果相等,则返回,其他进程也相应结束查找
{
printf("第%d个线程查找到该内容. ", pstruct->index);
*(pstruct->sflag) = 0; //标志位设为0;
*(pstruct->addr) = pbeg; //将找到的地址赋予结构体内的元素
return; //结束进行
}
}
printf("本线程%d无能,没有找到该元素。 ", pstruct->index);
return; //正常结束
}
void main()
{
int arr[1000] = { 0 }; //从1000个数中查找num;
for (int i = 0; i < 1000; i++) //为数组赋值
arr[i] = i + 1;
int num = 0;
printf("请输入要查找的数字(仅限于0到999的整数类型):");
scanf("%d", &num);
struct MultiSearch ms[10]; //申请十个结构类型,为避免各个线程之间的数据交叉,使每个线程中的数据都是独立的
for (int i = 0; i < 10; i++) //创建10个线程进行查找,每个线程查找其中的一百个元素
{
ms[i].beg = arr + i * 100;
ms[i].len = 100;
ms[i].data = num;
ms[i].sflag = &flag;
ms[i].addr = &destPtr;
ms[i].index = i;
_beginthread(find, 0, &ms[i]);
Sleep(50); //为创建进程留出时间
}
Sleep(3000); //等待查找结束
system("pause"); //如果主线程结束了,则其他的线程也相应结束了,因此要为主线程预留足够多的时间
printf(" %p, %d ", destPtr, *destPtr); //打印该元素的地址及其该地址所对应的数据
system("pause");
}
请输入要查找的数字(仅限于0到999的整数类型):888
本线程0无能,没有找到该元素。
第8个线程查找到该内容.
本线程7无能,其他线程已经找到。
本线程4无能,其他线程已经找到。
本线程1无能,其他线程已经找到。
本线程6无能,其他线程已经找到。
本线程3无能,其他线程已经找到。
本线程9无能,其他线程已经找到。
本线程5无能,其他线程已经找到。
本线程2无能,其他线程已经找到。
请按任意键继续. . .
- 004CF894, 888
- 请按任意键继续. . .