当前位置:文档之家› ThreadGroup线程组应用

ThreadGroup线程组应用

ThreadGroup线程组应用
ThreadGroup线程组应用

ThreadGroup线程组应用

一、基本方法

1、获取当前线程组名

[java] view plain copy 在CODE上查看代码片派生到我的代码片Thread.currentThread().getThreadGroup().getName()

在main方法是调用输出是:main

2、将线程放入到一个线程组中去

[java] view plain copy 在CODE上查看代码片派生到我的代码片ThreadGroup threadGroup1 = new ThreadGroup("group1"); ThreadGroup threadGroup2 = new ThreadGroup("group2");

Thread thread1 =new Thread(threadGroup1, "group1's member"); Thread thread2 =new Thread(threadGroup2, "group2's member");

其中Thread中和ThreadGroup相关的构造函数:

[java] view plain copy 在CODE上查看代码片派生到我的代码片public Thread(ThreadGroup group, Runnable target) {

init(group, target, "Thread-" + nextThreadNum(), 0);

}

public Thread(ThreadGroup group, String name) {

init(group, null, name, 0);

}

public Thread(ThreadGroup group, Runnable target, String name) { init(group, target, name, 0);

}

public Thread(ThreadGroup group, Runnable target, String name,

long stackSize) {

init(group, target, name, stackSize);

}

它们最终都是调用同一个函数:

[java] view plain copy 在CODE上查看代码片派生到我的代码片private void init(ThreadGroup g, Runnable target, String name,

long stackSize) {

Thread parent = currentThread();

SecurityManager security = System.getSecurityManager();

if (g == null) {

//安全检查

if (security != null) {

g = security.getThreadGroup();

}

//设置线程组

if (g == null) {

g = parent.getThreadGroup();

}

}

//检查可达性

g.checkAccess();

//是否有权限访问

if (security != null) {

if (isCCLOverridden(getClass())) {

security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);

}

}

//往线程组添加线程但未启动

g.addUnstarted();

this.group = g;

this.daemon = parent.isDaemon();//是否守护线程

this.priority = parent.getPriority();//优先级

https://www.doczj.com/doc/0a15329378.html, = name.toCharArray();

if (security == null || isCCLOverridden(parent.getClass()))

this.contextClassLoader = parent.getContextClassLoader();

else

this.contextClassLoader = parent.contextClassLoader;

this.inheritedAccessControlContext = AccessController.getContext();

this.target = target;

setPriority(priority);

if (parent.inheritableThreadLocals != null)

this.inheritableThreadLocals =

ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

this.stackSize = stackSize;

tid = nextThreadID();

this.me = this;

}

3、复制线程组:

[java] view plain copy 在CODE上查看代码片派生到我的代码片

//这样可以复制group里面的thread信息

Thread[] threads = new Thread[threadGroup.activeCount()];

threadGroup.enumerate(threads);

这里的activeCount很明显就是取得活动的线程,注意。默认情况下,连同其子线程组也会进行复制。

4、未捕获异常处理

ThreadGroup中有一个uncaughtException()方法。当线程组中某个线程发生Unchecked exception异常时,由执行环境调用此方法进行相关处理,如果有必要,可以重新定义此方法

二、应用实例

1、实例应用

[java] view plain copy 在CODE上查看代码片派生到我的代码片

package com.func.axc.threadgroup;

import java.util.Date;

import java.util.Random;

import java.util.concurrent.TimeUnit;

class Result {

private String name;

public String getName() {

return name;

}

public void setName(String name) {

https://www.doczj.com/doc/0a15329378.html, = name;

}

}

public class SearchTask implements Runnable {

public SearchTask(Result result) {

this.result = result;

}

private Result result;

@Override

public void run() {

String name = Thread.currentThread().getName();

System.out.println("Thread Start " + name);

try {

doTask();

result.setName(name);

} catch (InterruptedException e) {

System.out.printf("Thread %s: Interrupted\n", name);

return;

}

System.out.println("Thread end " + name);

}

private void doTask() throws InterruptedException {

Random random = new Random((new Date()).getTime());

int value = (int) (random.nextDouble() * 100);

System.out.printf("Thread %s: %d\n", Thread.currentThread().getName(), value);

TimeUnit.SECONDS.sleep(value);

}

public static void main(String[] args) {

System.out.println("main thread start:");

//创建5个线程,并入group里面进行管理

ThreadGroup threadGroup = new ThreadGroup("Searcher");

Result result = new Result();

SearchTask searchTask = new SearchTask(result);

for (int i = 0; i < 5; i++) {

Thread thred = new Thread(threadGroup, searchTask);

thred.start();

try {

TimeUnit.SECONDS.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

//通过这种方法可以看group里面的所有信息

System.out.printf("Number of Threads: %d\n", threadGroup.activeCount());

System.out.printf("Information about the Thread Group\n");

threadGroup.list();

//这样可以复制group里面的thread信息

Thread[] threads = new Thread[threadGroup.activeCount()];

https://www.doczj.com/doc/0a15329378.html,(threads);

for (int i = 0; i < threadGroup.activeCount(); i++) {

System.out.printf("Thread %s: %s\n", threads[i].getName(),

threads[i].getState());

}

waitFinish(threadGroup);

//将group里面的所有线程都给interpet

threadGroup.interrupt();

System.out.println("main thread end:");

}

private static void waitFinish(ThreadGroup threadGroup) { while (threadGroup.activeCount() > 0) {

try {

TimeUnit.SECONDS.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

输出结果:

2、统一异常处理实例

[java] view plain copy 在CODE上查看代码片派生到我的代码片package com.func.axc.threadgroup;

/**

* 功能概要:

*

* @author linbingwen

* @since 2016年6月11日

*/

public class ThreadGroupDemo {

public static void main(String[] args) {

ThreadGroup threadGroup1 =

// 这是匿名类写法

new ThreadGroup("group1") {

// 继承ThreadGroup并重新定义以下方法

// 在线程成员抛出unchecked exception

// 会执行此方法

public void uncaughtException(Thread t, Throwable e) {

System.out.println(t.getName() + ": " + e.getMessage());

}

};

// 这是匿名类写法

Thread thread1 =

// 这个线程是threadGroup1的一员

new Thread(threadGroup1, new Runnable() {

public void run() {

// 抛出unchecked异常

throw new RuntimeException("测试异常");

}

});

thread1.start();

}

}

三、源码解读

首先看其包含的变量

[java] view plain copy 在CODE上查看代码片派生到我的代码片

public class ThreadGroup implements Thread.UncaughtExceptionHandler { private final ThreadGroup parent;//父亲ThreadGroup

String name;//ThreadGroupr 的名称

int maxPriority;//线程最大优先级

boolean destroyed;//是否被销毁

boolean daemon;//是否守护线程

boolean vmAllowSuspension;//是否可以中断

int nUnstartedThreads = 0;//还未启动的线程

int nthreads;//ThreadGroup中线程数目

Thread threads[];//ThreadGroup中的线程

int ngroups;//线程组数目

ThreadGroup groups[];//线程组数组

从源码中可以看出,其包含的变量并不是很多。这里需要注意

(1)线程组也可以包含其他线程组。如上面的groups[].

(2)线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组构造函数:

[java] view plain copy 在CODE上查看代码片派生到我的代码片

//私有构造函数

private ThreadGroup() {

https://www.doczj.com/doc/0a15329378.html, = "system";

this.maxPriority = Thread.MAX_PRIORITY;

this.parent = null;

}

//默认是以当前ThreadGroup传入作为parent ThreadGroup,新线程组的父线程组是目前正在运行线程的线程组。

public ThreadGroup(String name) {

this(Thread.currentThread().getThreadGroup(), name);

}

//构造函数

public ThreadGroup(ThreadGroup parent, String name) {

this(checkParentAccess(parent), parent, name);

}

//私有构造函数

private ThreadGroup(Void unused, ThreadGroup parent, String name) {

https://www.doczj.com/doc/0a15329378.html, = name;

this.maxPriority = parent.maxPriority;

this.daemon = parent.daemon;

this.vmAllowSuspension = parent.vmAllowSuspension;

this.parent = parent;

parent.add(this);

}

其终的调用构造函数只有一个,父线程组的checkAccess 方法在checkParentAccess中会调用:

[java] view plain copy 在CODE上查看代码片派生到我的代码片

//检查parent ThreadGroup

private static Void checkParentAccess(ThreadGroup parent) {

parent.checkAccess();

return null;

}

未捕获异常设置:

[java] view plain copy 在CODE上查看代码片派生到我的代码片

public void uncaughtException(Thread t, Throwable e) {

if (parent != null) {

parent.uncaughtException(t, e);//父线程组不为空,设置到父线程组

} else {

Thread.UncaughtExceptionHandler ueh =

Thread.getDefaultUncaughtExceptionHandler();

if (ueh != null) {

ueh.uncaughtException(t, e);

} else if (!(e instanceof ThreadDeath)) {

System.err.print("Exception in thread \""

+ t.getName() + "\" ");

e.printStackTrace(System.err);

}

}

}

如果父线程组存在, 则调用它的uncaughtException方法.

如果父线程组不存在, 但指定了默认处理器(下节中的As the default handler for the application), 则调用默认的处理器

如果默认处理器没有设置, 则写错误日志.但如果exception是ThreadDeath实例的话, 忽略

线程组复制:

[java] view plain copy 在CODE上查看代码片派生到我的代码片

//此线程组及其子组中的所有活动线程复制到指定数组中。

public int enumerate(ThreadGroup list[]) {

checkAccess();

return enumerate(list, 0, true);

}

//此线程组及其子组中的所有活动线程复制到指定数组中。

public int enumerate(ThreadGroup list[], boolean recurse) {

checkAccess();

return enumerate(list, 0, recurse);

}

//此线程组中的所有活动线程复制到指定数组中。如果recurse 标志为true,则还包括对此线程的子组中的所有活动线程的引用。如果数组太小而无法保持所有线程,则//忽略额外的线程。

private int enumerate(ThreadGroup list[], int n, boolean recurse) {

int ngroupsSnapshot = 0;

ThreadGroup[] groupsSnapshot = null;

synchronized (this) {

if (destroyed) {

return 0;

}

int ng = ngroups;

if (ng > list.length - n) {//防止list放不下线程数目

ng = list.length - n;

}

if (ng > 0) {

System.arraycopy(groups, 0, list, n, ng);//复制线程组

n += ng;

}

if (recurse) { //取得其子组

ngroupsSnapshot = ngroups;

if (groups != null) {

groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);

} else {

groupsSnapshot = null;

}

}

}

if (recurse) {//复制子组

for (int i = 0 ; i < ngroupsSnapshot ; i++) {

n = groupsSnapshot[i].enumerate(list, n, true);

}

}

return n;

}

多线程编程的详细说明完整版

VB .NET多线程编程的详细说明 作者:陶刚整理:https://www.doczj.com/doc/0a15329378.html, 更新时间:2011-4-1 介绍 传统的Visual Basic开发人员已经建立了同步应用程序,在这些程序中事务按顺序执行。尽管由于多个事务多多少少地同时运行使多线程应用程序效率更高,但是使用先前版本的Visual Basic很难建立这类程序。 多线程程序是可行的,因为操作系统是多任务的,它有模拟同一时刻运行多个应用程序的能力。尽管多数个人计算机只有一个处理器,但是现在的操作系统还是通过在多个执行代码片断之间划分处理器时间提供了多任务。线程可能是整个应用程序,但通常是应用程序可以单独运行的一个部分。操作系统根据线程的优先级和离最近运行的时间长短给每一个线程分配处理时间。多线程对于时间密集型事务(例如文件输入输出)应用程序的性能有很大的提高。 但是也有必须细心的地方。尽管多线程能提高性能,但是每个线程还是需要用附加的内存来建立和处理器时间来运行,建立太多的线程可能降低应用程序的性能。当设计多线程应用程序时,应该比较性能与开销。 多任务成为操作系统的一部分已经很久了。但是直到最近Visual Basic程序员才能使用无文档记录特性(undocumented)或者间接使用COM组件或者操作系统的异步部分执行多线程事务。.NET框架组件为开发多线程应用程序,在System.Threading名字空间中提供了全面的支持。 本文讨论多线程的好处以及怎样使用Visual Basic .NET开发多线程应用程序。尽管Visual Basic .NET和.NET框架组件使开发多线程应用程序更容易,但是本文作了调整使其适合高级读者和希望从早期Visual Basic转移到Visual Basic .NET的开发人员。 多线程处理的优点 尽管同步应用程序易于开发,但是它们的性能通常比多线程应用程序低,因为一个新的事务必须等待前面的事务完成后才能开始。如果完成某个同步事务的时间比预想的要长,应用程序可能没有响应。多线程处理可以同时运行多个过程。例如,字处理程序能够在继续操作文档的同时执行拼写检查事务。因为多线程应用程序把程序分解为独立的事务,它们能通过下面的途径充分提高性能: l 多线程技术可以使程序更容易响应,因为在其它工作继续时用户界面可以保持激活。 l 当前不忙的事务可以把处理器时间让给其它事务。 l 花费大量处理时间的事务可以周期性的把时间让给其它的事务。 l 事务可以在任何时候停止。 l 可以通过把单独事务的优先级调高或调低来优化性能。 明确地建立多线程应用程序的决定依赖于几个因素。多线程最适合下面的情况:

实验2-2windows2000 线程同步

实验2 并发与调度 2.2 Windows 2000线程同步 (实验估计时间:120分钟) 背景知识 实验目的 工具/准备工作 实验内容与步骤 背景知识 Windows 2000提供的常用对象可分成三类:核心应用服务、线程同步和线程间通讯。其中,开发人员可以使用线程同步对象来协调线程和进程的工作,以使其共享信息并执行任务。此类对象包括互锁数据、临界段、事件、互斥体和信号等。 多线程编程中关键的一步是保护所有的共享资源,工具主要有互锁函数、临界段和互斥体等;另一个实质性部分是协调线程使其完成应用程序的任务,为此,可利用内核中的事件对象和信号。 在进程内或进程间实现线程同步的最方便的方法是使用事件对象,这一组内核对象允许一个线程对其受信状态进行直接控制 (见表4-1) 。 而互斥体则是另一个可命名且安全的内核对象,其主要目的是引导对共享资源的访问。拥有单一访问资源的线程创建互斥体,所有想要访问该资源的线程应该在实际执行操作之前获得互斥体,而在访问结束时立即释放互斥体,以允许下一个等待线程获得互斥体,然后接着进行下去。 与事件对象类似,互斥体容易创建、打开、使用并清除。利用CreateMutex() API 可创建互斥体,创建时还可以指定一个初始的拥有权标志,通过使用这个标志,只有当线程完成了资源的所有的初始化工作时,才允许创建线程释放互斥体。

为了获得互斥体,首先,想要访问调用的线程可使用OpenMutex() API来获得指向对象的句柄;然后,线程将这个句柄提供给一个等待函数。当内核将互斥体对象发送给等待线程时,就表明该线程获得了互斥体的拥有权。当线程获得拥有权时,线程控制了对共享资源的访问——必须设法尽快地放弃互斥体。放弃共享资源时需要在该对象上调用ReleaseMute() API。然后系统负责将互斥体拥有权传递给下一个等待着的线程(由到达时间决定顺序) 。 实验目的 在本实验中,通过对事件和互斥体对象的了解,来加深对Windows 2000线程同步的理解。 1) 回顾系统进程、线程的有关概念,加深对Windows 2000线程的理解。 2) 了解事件和互斥体对象。 3) 通过分析实验程序,了解管理事件对象的API。 4) 了解在进程中如何使用事件对象。 5) 了解在进程中如何使用互斥体对象。 6) 了解父进程创建子进程的程序设计方法。 工具/准备工作 在开始本实验之前,请回顾教科书的相关内容。 您需要做以下准备: 1) 一台运行Windows 2000 Professional操作系统的计算机。 2) 计算机中需安装Visual C++ 6.0专业版或企业版。 实验内容与步骤 1. 事件对象 2. 互斥体对象 1. 事件对象 清单2-1程序展示了如何在进程间使用事件。父进程启动时,利用CreateEvent() API创建一个命名的、可共享的事件和子进程,然后等待子进程向事件发出信号并终止父进程。在创建时,子进程通过OpenEvent() API打开事件对象,调用SetEvent() API使其转化为已接受信号状态。两个进程在发出信号之后几乎立即终止。 步骤1:登录进入Windows 2000 Professional。 步骤2:在“开始”菜单中单击“程序”-“Microsoft Visual Studio 6.0”–“Microsoft Visual C++ 6.0”命令,进入Visual C++窗口。

解决多线程中11个常见问题

并发危险 解决多线程代码中的11 个常见的问题 Joe Duffy 本文将介绍以下内容:?基本并发概念 ?并发问题和抑制措施 ?实现安全性的模式?横切概念本文使用了以下技术: 多线程、.NET Framework 目录 数据争用 忘记同步 粒度错误 读写撕裂 无锁定重新排序 重新进入 死锁 锁保护 戳记 两步舞曲 优先级反转 实现安全性的模式 不变性 纯度 隔离 并发现象无处不在。服务器端程序长久以来都必须负责处理基本并发编程模型,而随着多核处理器的日益普及,客户端程序也将需要执行一些任务。随着并发操作的不断增加,有关确保安全的问题也浮现出来。也就是说,在面对大量逻辑并发操作和不断变化的物理硬件并行性程度时,程序必须继续保持同样级别的稳定性和可靠性。 与对应的顺序代码相比,正确设计的并发代码还必须遵循一些额外的规则。对内存的读写以及对共享资源的访问必须使用同步机制进行管制,以防发生冲突。另外,通常有必要对线程进行协调以协同完成某项工作。 这些附加要求所产生的直接结果是,可以从根本上确保线程始终保持一致并且保证其顺利向前推进。同步和协调对时间的依赖性很强,这就导致了它们具有不确定性,难于进行预测和测试。 这些属性之所以让人觉得有些困难,只是因为人们的思路还未转变过来。没有可供学习的专门API,也没有可进行复制和粘贴的代码段。实际上的确有一组基础概念需要您学习和适应。很可能随着时间的推移某些语言和库会隐藏一些概念,但如果您现在就开始执行并发操作,则不会遇到这种情况。本

文将介绍需要注意的一些较为常见的挑战,并针对您在软件中如何运用它们给出一些建议。 首先我将讨论在并发程序中经常会出错的一类问题。我把它们称为“安全隐患”,因为它们很容易发现并且后果通常比较严重。这些危险会导致您的程序因崩溃或内存问题而中断。 当从多个线程并发访问数据时会发生数据争用(或竞争条件)。特别是,在一个或多个线程写入一段数据的同时,如果有一个或多个线程也在读取这段数据,则会发生这种情况。之所以会出现这种问题,是因为Windows 程序(如C++ 和Microsoft .NET Framework 之类的程序)基本上都基于共享内存概念,进程中的所有线程均可访问驻留在同一虚拟地址空间中的数据。静态变量和堆分配可用于共享。请考虑下面这个典型的例子: static class Counter { internal static int s_curr = 0; internal static int GetNext() { return s_curr++; } } Counter 的目标可能是想为GetNext 的每个调用分发一个新的唯一数字。但是,如果程序中的两个线程同时调用GetNext,则这两个线程可能被赋予相同的数字。原因是s_curr++ 编译包括三个独立的步骤: 1.将当前值从共享的s_curr 变量读入处理器寄存器。 2.递增该寄存器。 3.将寄存器值重新写入共享s_curr 变量。 按照这种顺序执行的两个线程可能会在本地从s_curr 读取了相同的值(比如42)并将其递增到某个值(比如43),然后发布相同的结果值。这样一来,GetNext 将为这两个线程返回相同的数字,导致算法中断。虽然简单语句s_curr++ 看似不可分割,但实际却并非如此。 忘记同步 这是最简单的一种数据争用情况:同步被完全遗忘。这种争用很少有良性的情况,也就是说虽然它们是正确的,但大部分都是因为这种正确性的根基存在问题。 这种问题通常不是很明显。例如,某个对象可能是某个大型复杂对象图表的一部分,而该图表恰好可使用静态变量访问,或在创建新线程或将工作排入线程池时通过将某个对象作为闭包的一部分进行传递可变为共享图表。 当对象(图表)从私有变为共享时,一定要多加注意。这称为发布,在后面的隔离上下文中会对此加以讨论。反之称为私有化,即对象(图表)再次从共享变为私有。 对这种问题的解决方案是添加正确的同步。在计数器示例中,我可以使用简单的联锁: static class Counter { internal static volatile int s_curr = 0; internal static int GetNext() { return Interlocked.Increment(ref s_curr);

多线程技术在Android手机开发中的运用

龙源期刊网 https://www.doczj.com/doc/0a15329378.html, 多线程技术在Android手机开发中的运用 作者:谢光刘志惠 来源:《电子技术与软件工程》2017年第24期 摘要 在Android手机开发过程中,一般情况下程序是通过一个线程进行工作的,因此当一个任务耗费过长时间,就会造成主程序无响应并对程序运行的顺畅程度造成影响的问题。基于此,本文通过对多线程组成进行介绍,在Android中多线程技术模块与具体实现方式两方面对多线程技术在安卓手机开发中的运用进行探讨,以为关注此问题的人们提供参考。 【关键词】多线程技术 Android手机进程线程 安卓系统自2007年由谷歌公司开发后,得到了巨大的发展。截至2017年3月,其市场占有率已经达到86.4%,如三星、索尼爱立信、小米、OPPO等手机生产厂商都在使用安卓系统。该系统开源免费、执行效率高,其多线程技术开发应用的研究,对提高手机硬件的利用效率,给用户带来良好试用体验,提高手机厂商的企业竞争力有重要作用。 1 多线程介绍 1.1 进程和线程介绍 一般来说,在一定时间内实现多个程序任务执行的程序都会用到“进程”这一概念。进程,即:一个拥有自身独立的内存空间、系统资源的执行程序,其特征为实现内部状态和内部数据的相互独立。线程与进程相似,线程也是一段有一定功能代码组成的流控制。线程的特征为:同类的多个线程可以对内存空间与系统资源进行共享。因此在对资源的占用方面,可以相互切换的线程比进程小很多。一个进程中可以包含诸多线程,此外,主线程对子线程有控制作用,可对子线程启动、停止等动作进行管理。而本文要重点介绍的多线程,指的是单个程序中一起运行的不同线程,不同线程可以执行不一样的任务。其特征是一个程序的多行语句可在某时间同时执行。 1.2 多线程程序消息处理原理 当人们启动一个程序时,系统将建立main线程,主要管理如:activity等应用组件,并对UI相关的事件进行处理,比如用户想要按键或使用屏幕进行绘图,线程会对以上事件进行处理,这是UI线程。安卓的线程模型,所有组件均在main线程中,因此用户在程序中下达下载文件、使用数据库等具有高耗时特征的操作时,就会造成UI线程的运行不畅,并出现程序无法响应的问题。这就要求程序员使用多线程技术,在进行安卓多线程编写时,技术人员应注意以下两点:

基于多线程的高性能服务器程序的设计

基于多线程的高性能服务器程序的设计 摘要:随着网络应用的迅猛发展,高性能服务器程序越来越凸显出其重要地位。 文中基于多线程设计了高性能服务器程序,从而对处理客户端的并发请求问题提出了很好的解决方案。文中首先介绍了IOCP模型的原理,接着分别运用Select 模型和IOCP模型对高性能服务器程序的设计提出了不同的设计方法,通过比较时间、CPU的利用率和内存的使用率等参数,得出IOCP在设计服务器上提供了最佳的系统性能。最后提出了高性能服务器程序的设计方案。 关键字:Select 模型;IOCP模型;并发控制;事件;流的控制 1引言 目前很多服务器程序都是采用“一对一”处理模式,即一个客户占用一个线程,基于这种模式的服务器程序在框架上设计很简单,但是由于采用的是“一客户/一线程”的模式,所以这种服务器程序对于上千客户的请求连接,其在性能上就显得很低,在系统资源上的开销也很大。由于操作系统必须为大量的线程进行调度,从而会损耗大量的系统资源,另外互斥控制也会显得很困难,死锁发生的频率也会大幅度的增大。 现如今高性能服务器程序的设计显得越来越重要,高性能服务器程序的主要作用是能够高效的处理大量并发客户的请求,并且快速及时的处理客户的数据,同时将部分应答信息回传给客户端。要设计好一个性能优良的服务器程序,要考虑很多方面的因素,如CPU的使用率、Memory的开销等。要想做到高效处理并发用户的请求,服务器程序就需要解决两个主要的问题,一是处理并发客户的连接请求,二是对并发数据的处理。要解决这些问题,可以根据处理器内核的数量,来创建等量的工作线程,并结合IOCP(Input/Output Completion Port,IOCP))模型,以及操作系统的线程调度机制。文中采用多线程并结合IOCP模型对高性能的服务器程序设计进行了深入的探讨。 2 IOCP模型原理 IOCP(I/O Completion Port 输入/输出完成端口)是一种能够合理利用与管理多线程的机制。它是迄今为止Windows平台上最为复杂的一种I/O模型,当应用程序必须一次管理多个套接字时,完成端口模型提供了最好的系统性能,这个模型也提供了最好的伸缩性,非常适合用来处理上百、上千个客户。 IOCP模型提供了一个高效复杂的内核对象,该对象通过指定数量的线程,可

用多线程同步方法解决生产者-消费者问题(操作系统课设)

. 题目用多线程同步方法解决生产者-消费 者问题(Producer-Consumer Problem) 学院计算机科学与技术学院 专业软件工程 班级 姓名 指导教师 年月日

目录 目录 (1) 课程设计任务书 (2) 正文 (2) 1.设计目的与要求 (2) 1.1设计目的 (2) 1.2设计要求 (2) 2.设计思想及系统平台 (2) 2.1设计思想 (2) 2.2系统平台及使用语言 (2) 3.详细算法描述 (3) 4.源程序清单 (5) 5.运行结果与运行情况 (10) 6.调试过程 (15) 7.总结 (15) 本科生课程设计成绩评定表 (16)

课程设计任务书 学生姓名:专业班级: 指导教师:工作单位:计算机科学与技术学院 题目: 用多线程同步方法解决生产者-消费者问题 (Producer-Consumer Problem) 初始条件: 1.操作系统:Linux 2.程序设计语言:C语言 3.有界缓冲区内设有20个存储单元,其初值为0。放入/取出的数据项按增序设定为1-20这20个整型数。 要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写等具体要 求) 1.技术要求: 1)为每个生产者/消费者产生一个线程,设计正确的同步算法 2)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的当前全部内容、当前指针位置和生产者/消费者线程的自定义标识符。 3)生产者和消费者各有两个以上。 4)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。 2.设计说明书内容要求: 1)设计题目与要求 2)总的设计思想及系统平台、语言、工具等。 3)数据结构与模块说明(功能与流程图) 4)给出用户名、源程序名、目标程序名和源程序及其运行结果。(要注明存储各个程序及其运行结果的主机IP地址和目录。) 5)运行结果与运行情况 (提示: (1)有界缓冲区可用数组实现。 (2)编译命令可用:cc -lpthread -o 目标文件名源文件名 (3)多线程编程方法参见附件。) 3. 调试报告: 1)调试记录 2)自我评析和总结 上机时间安排: 18周一~ 五 08:0 - 12:00 指导教师签名:年月日

第5章-多线程-补充案例

第五章补充案例 案例5-1继承Thread类创建多线程 一、案例描述 1、考核知识点 编号:00105002 名称:继承Thread类创建多线程 2、练习目标 ?掌握如何通过继承Thread类实现多线程的创建。 ?掌握Thread类中run()方法和start()方法的使用。 3、需求分析 在程序开发中,会遇到一个功能需要多个线程同时执行才能完成的情况。这时,可以通过继承线程类Thread,并重写Thread类中的run()方法来实现。为了让初学者熟悉如何创建多线程,在案例中将通过继承Thread类方式创建线程,并实现多线程分别打印0~99的数字的功能。 4、设计思路(实现原理) 1)自定义一个类Demo,使其继承Thread类。 2)在Demo类中重写run()方法,在run()方法内编写一个for循环,循环体内打印:“Demo:” +当前循环次数。 3)编写测试类Example01,在Example01类的main()方法中,创建一个Demo对象,并执 行其start()方法,接着编写一个for循环,循环体内打印:“main:”+当前循环次数。

二、案例实现 class Demo extends Thread { public void run() { for (int x = 0; x < 100; x++) { System.out.println("Demo:"+x); } } } public class Example01{ public static void main(String[] args) { Demo d = new Demo(); d.start(); for(int x=0; x<100; x++){ System.out.println("main:"+x); } } } 运行结果如图5-1所示。 图5-1运行结果 三、案例总结 1、通过继承Thread类,并重写Thread类中的run()方法可以实现多线程。 2、Thread类中,提供的start()方法用于启动新线程,线程启动后,系统会自动调用run()方法。 3、main()方法中有一条主线程在运行。

多线程同步操作多个窗口

多线程同步操作多个窗口 RunApp "notepad.exe" RunApp "notepad.exe" RunApp "notepad.exe" Delay 2000 Dimenv temp_Hwnd temp_Hwnd = 0 Dim str, arr, i str = Plugin.Window.Search("无标题- 记事本") arr = Split(str, "|") For i = 0 To UBound(arr) - 1 temp_Hwnd = Plugin.Window.FindEx(arr(i), 0, "Edit", 0) BeginThread WriteString While temp_Hwnd <> 0'判断多线程已经启动完毕,继续循环下一个。 Delay 500 Wend Next EndScript Function WriteString() Dim str, Hwnd Hwnd = temp_Hwnd temp_Hwnd = 0 Do str = WaitKey If Hwnd <> Plugin.Window.GetKeyFocusWnd Then Call Plugin.Bkgnd.KeyPress(Hwnd, str) End If Loop End Function 多线程多开窗口同步执行与子线程间的数值如何传递: 1.Dimenv IsThread, i 2.Dim arr_Thread() 3.For i = 0 To 2 4. IsThread = False'未启动线程 5. Redim Preserve arr_Thread(i) 6. arr_Thread(i) = BeginThread(EnterThread) 7. While IsThread = False'未启动成功,等待中 8. Delay 500 9. Wend 10. '跳出循环说明 IsThread = True,已经执行到了,循环继续启动下一个 11.Next

C++多线程编程入门及范例详解

多线程编程之一——问题提出 一、问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG 添加一个按钮,ID为IDC_SLEEP_SIX_SECOND,标题为“延时6秒”,添加按钮的响应函数,代码如下: 1.void CSingleThreadDlg::OnSleepSixSecond() 2.{ 3.Sleep(6000);//延时6秒 4.} 编译并运行应用程序,单击“延时6秒”按钮,你就会发现在这6秒期间程序就象“死机”一样,不在响应其它消息。为了更好地处理这种耗时的操作,我们有必要学习——多线程编程。 二、多线程概述 进程和线程都是操作系统的概念。进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放或关闭。 线程是进程内部的一个执行单元。系统创建好进程后,实际上就启动执行了该进程的主执行线程,主执行线程以函数地址形式,比如说main或WinMain函数,将程序的启动点提供给Windows 系统。主执行线程终止了,进程也就随之终止。 每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同一个进程中。一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用这些虚拟地址空间、全局变量和系统资源,所以线程间的通讯非常方便,多线程技术的应用也较为广泛。 多线程可以实现并行处理,避免了某项任务长时间占用CPU时间。要说明的一点是,目前大多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,操作系统为每个独立线程安排一些CPU时间,操作系统以轮换方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。由此可见,如果两个非常活跃的线程为了抢夺对CPU的控制权,在线程切换时会消耗很多的CPU资源,反而会降低系统的性能。这一点在多线程编程时应该注意。 Win32SDK函数支持进行多线程的程序设计,并提供了操作系统原理中的各种同步、互斥和临界区等操作。Visual C++6.0中,使用MFC类库也实现了多线程的程序设计,使得多线程编程更加方便。 三、Win32API对多线程编程的支持 Win32提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作。下面将选取其中的一些重要函数进行说明。

4:一个经典的多线程同步问题汇总

一个经典的多线程同步问题 程序描述: 主线程启动10个子线程并将表示子线程序号的变量地址作为参数传递给子线程。子线程接收参数 -> sleep(50) -> 全局变量++ -> sleep(0) -> 输出参数和全局变量。 要求: 1.子线程输出的线程序号不能重复。 2.全局变量的输出必须递增。 下面画了个简单的示意图: 分析下这个问题的考察点,主要考察点有二个: 1.主线程创建子线程并传入一个指向变量地址的指针作参数,由于线程启动须要花费一定的时间,所以在子线程根据这个指针访问并保存数据前,主线程应等待子线程保存完毕后才能改动该参数并启动下一个线程。这涉及到主线程与子线程之间的同步。 2.子线程之间会互斥的改动和输出全局变量。要求全局变量的输出必须递增。这涉及到各子线程间的互斥。 下面列出这个程序的基本框架,可以在此代码基础上进行修改和验证。 //经典线程同步互斥问题 #include #include #include long g_nNum; //全局资源 unsigned int__stdcall Fun(void *pPM); //线程函数 const int THREAD_NUM = 10; //子线程个数 int main() { g_nNum = 0;

HANDLE handle[THREAD_NUM]; int i = 0; while (i < THREAD_NUM) { handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL); i++;//等子线程接收到参数时主线程可能改变了这个i的值} //保证子线程已全部运行结束 WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE); return 0; } unsigned int__stdcall Fun(void *pPM) { //由于创建线程是要一定的开销的,所以新线程并不能第一时间执行到这来int nThreadNum = *(int *)pPM; //子线程获取参数 Sleep(50);//some work should to do g_nNum++; //处理全局资源 Sleep(0);//some work should to do printf("线程编号为%d 全局资源值为%d\n", nThreadNum, g_nNum); return 0; } 运行结果:

四种进程或线程同步互斥的控制方法

四种进程或线程同步互斥的控制方法 1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。 2、互斥量:为协调共同对一个共享资源的单独访问而设计的。 3、信号量:为控制一个具有有限数量用户资源而设计。 4、事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。 一临界区 临界区的使用在线程同步中应该算是比较简单,说它简单还是说它同后面讲到的其它方法相比更容易理解。举个简单的例子:比如说有一个全局变量(公共资源)两个线程都会对它进行写操作和读操作,如果我们在这里不加以控制,会产生意想不到的结果。假设线程A 正在把全局变量加1然后打印在屏幕上,但是这时切换到线程B,线程B又把全局变量加1然后又切换到线程A,这时候线程A打印的结果就不是程序想要的结果,也就产生了错误。解决的办法就是设置一个区域,让线程A在操纵全局变量的时候进行加锁,线程B如果想操纵这个全局变量就要等待线程A释放这个锁,这个也就是临界区的概念。 二互斥体 windows api中提供了一个互斥体,功能上要比临界区强大。也许你要问,这个东东和临界区有什么区别,为什么强大?它们有以下几点不一致: 1.critical section是局部对象,而mutex是核心对象。因此像waitforsingleobject是不可以等待临界区的。 2.critical section是快速高效的,而mutex同其相比要慢很多 3.critical section使用围是单一进程中的各个线程,而mutex由于可以有一个名字,因此它是可以应用于不同的进程,当然也可以应用于同一个进程中的不同线程。 4.critical section 无法检测到是否被某一个线程释放,而mutex在某一个线程结束之后会产生一个abandoned的信息。同时mutex只能被拥有它的线程释放。下面举两个应用mutex 的例子,一个是程序只能运行一个实例,也就是说同一个程序如果已经运行了,就不能再运行了;另一个是关于非常经典的哲学家吃饭问题的例子。 三事件 事件对象的特点是它可以应用在重叠I/O(overlapped I/0)上,比如说socket编程中有两种模型,一种是重叠I/0,一种是完成端口都是可以使用事件同步。它也是核心对象,因此可以被waitforsingleobje这些函数等待;事件可以有名字,因此可以被其他进程开启。 四信号量 semaphore的概念理解起来可能要比mutex还难,我先简单说一下创建信号量的函数,因为我在开始使用的时候没有很快弄清楚,可能现在还有理解不对的地方,如果有错误还是请大侠多多指教。 CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD LONG lInitialCount, // initial count LONG lMaximumCount, // maximum count LPCTSTR lpName // object name )

多线程编程实例

编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。 函数pthread_create用来创建一个线程,它的原型为:extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr, void *(*__start_routine) (void *), void *__arg)); 第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。当创建线程成功时,函数返回0,若不为0则说明创建线程失败。 函数pthread_join用来等待一个线程的结束。函数原型为:extern int pthread_join __P ((pthread_t __th, void **__thread_return)); 第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。 一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit来实现。它的函数原型为: extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));

最简单的线程程序: /* example.c*/ #include #include void thread(void) { int i; for(i=0;i<3;i++) printf("This is a pthread.\n"); } int main(void) { pthread_t id; int i,ret; ret=pthread_create(&id,NULL,(void *) thread,NULL); if(ret!=0){ printf ("Create pthread error!\n"); exit (1); } for(i=0;i<3;i++) printf("This is the main process.\n"); pthread_join(id,NULL); return (0); } 输出是什么样子?

用多线程同步方法解决生产者-消费者问题(操作系统课设)

用多线程同步方法解决生产者-消费者问题(操作系统课设)

题目 用多线程同步方法解决生产者-消费 者问题(Producer-Consume r Problem) 学院 物理学与电子信息工程学院 专业电子信息工程班级08电信本一班姓名 指导教师 2010 年12 月日

目录 目录 0 课程设计任务书 (1) 正文 (3) 1.设计目的与要求 (3) 1.1设计目的 (3) 1.2设计要求 (3) 2.设计思想及系统平台 (3) 2.1设计思想 (3) 2.2系统平台及使用语言 (3) 3.详细算法描述 (4) 4.源程序清单 (7) 5.运行结果与运行情况 (12) 6.调试过程 (16) 7.总结 (16)

课程设计任务书 题目: 用多线程同步方法解决生产者-消费者问题 (Producer-Consumer Problem) 初始条件: 1.操作系统:Linux 2.程序设计语言:C语言 3.有界缓冲区内设有20个存储单元,其初 值为0。放入/取出的数据项按增序设定为 1-20这20个整型数。 要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求) 1.技术要求: 1)为每个生产者/消费者产生一个线程,设计正确的同步算法 2)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的当前全部 内容、当前指针位置和生产者/消费者

线程的自定义标识符。 3)生产者和消费者各有两个以上。 4)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。 2.设计说明书内容要求: 1)设计题目与要求 2)总的设计思想及系统平台、语言、工具 等。 3)数据结构与模块说明(功能与流程图) 4)给出用户名、源程序名、目标程序名和源程序及其运行结果。(要注明存储各个 程序及其运行结果的主机IP地址和目 录。) 5)运行结果与运行情况 (提示: (1)有界缓冲区可用数组实现。 (2)编译命令可用:cc -lpthread -o 目标文件名源文件名 (3)多线程编程方法参见附件。) 3. 调试报告: 1)调试记录 2)自我评析和总结

经典多线程的练习题

java中有几种方法可以实现一个线程(jdk5.0之前)?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 答:有两种实现方法,分别是继承Thread类与实现Runnable接口。 用synchronized关键字修饰同步方法,反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果很难检查出真正的问题所在。 suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被"挂起"的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志, 指出线程应该活动还是挂起。若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。 sl eep() 和wait() 有什么区别? 答:sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。 wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 同步和异步有何异同,在什么情况下分别使用他们?举例说明。 答:如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。 当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。

第二章多线程分布式计算课后答案

第二章 1. 选择题 12345678910 D A B C C E C A B B 1112131415161718 B B B C A D A A 2. 程序/方法与进程/线程有什么不同?(53页第四段) 答:一个程序/方法是由程序员写的一段代码,它是静态的。进程/线程是由执行的程序/方法、当前值、状态信息和用于支持它执行的资源构成,资源是它执行时的动态因素。换言之,一个进程/线程是一个动态实体,只有当程序或函数执行时才会存在。 3. 比较多进程(多任务)操作系统和多线程编程环境。(53页5、 6、7段) 答:为了真正并行执行多个进程/线程,必须存在多个处理器。如果系统中只有一个处理器,表面上多个进程/线程执行,实际上实在分时模式下顺序执行。 从同一代码块可以创建多个进程/线程。默认情况下,包含在不同进程/线程中的代码和数据是分离的,每一个都有它自己执行代码的副本、局部变量的栈、对象数据区以及其他数据元素。 通常情况下,一个分布式操作系统可以由不同电脑上的多个实例或副本构成,每一个实例或副本都可以管理多个进程。同样,每个进程可以是由多个线程组成的一个多线程程序。 4. 什么是临界操作?用什么方法可以来保护临界操作?(54页第1 段) 答:对共享资源的访问称为临界操作。虽然一个简单的锁定可以防止共享资源被访问,但是也消除了并行处理的可能性。更理想的方法是不锁定并行读操作,而锁定并行读-写和写-写组合。 5. 什么是死锁?哪些策略可以用来解决死锁问题?(55页) 答:死锁的情况是两个或多个竞争操作等待对方完成,导致都不能完成。 解决方法: (1) 死锁预防:使用一种算法可以保证不会发生死锁。 (2) 死锁避免:使用一种算法,能够遇见死锁的发生从而拒绝资源请求、

多线程同步方法及比较

多线程同步方法及比较 多线程同步方法: 1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数 据访问。. 2.互斥量:为协调一起对一个共享资源的单独访问而设计的。. 3.信号量:为控制一个具备有限数量用户资源而设计。. 4.事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。 临界区(Critical Section).. 确保在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。假如有多个线程试图同时访问临界区,那么在有一个线程进入后其他任何试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程能够继续抢占,并以此达到用原子方式操作共享资源的目的。 临界区包含两个操作原语: EnterCriticalSection()进入临界区 LeaveCriticalSection()离开临界区。 EnterCriticalSection()语句执行后代码将进入临界区以后无论发生什么,必须确保和之匹配的LeaveCriticalSection()都能够被执行到。否则临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。 MFC为临界区提供有一个CCriticalSection类,使用该类进行线程同步处理是很简单的。只需在线程函数中用CCriticalSection类成员函数Lock()和UnLock()标定出被保护代码片段即可。Lock()后代码用到的资源自动被视为临界区内的资源被保护。UnLock后别的线程才能访问这些资源。. ------------------------------------------------

易语言多线程详解

前记:无意中发现的一个关于易语言多线程的讲解,分享给大家,有用得着的看看。其中还提供了关于限制多开的办法,仔细阅读发现吧。(BY挂茶馆) 一、关于多线程冲突问题。 3.6版开始增加了多线程支持库,提供对多线程的支持,并通过实现进入许可证机制以避免多线程冲突。 多线程是这样一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立。线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。 多个线程的执行是并发的,也就是在逻辑上“同时”,而不管是否是物理上的“同时”。如果系统只有一个CPU,那么真正的“同时”是不可能的,但是由于CPU的速度非常快,用户感觉不到其中的区别,因此我们也不用关心它,只需要设想各个线程是同时执行即可。 多线程和传统的单线程在程序设计上最大的区别在于,由于各个线程的控制流彼此独立,使得各个线程之间的代码是乱序执行的,由此带来的线程调度,同步等问题,将在下面探讨。 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。 多线程也有它不利的一面。任何时候某个应用程序使用的线程多于一个时,如果多个线程在同一时刻试图使用相同的数据或资源,可能出现麻烦。这种情况一旦出现,程序将变得非常复杂并且难以调试。 更糟的是多线程代码经常在最初开发时运行良好,在形成产品时却往往失败,原因在于有未被发现的多个线程与相同的数据或资源相互作用的情况。这使得多线程编程非常危险。 因此,在编程时需要考虑在多个线程访问同一资源时产生冲突的问题:当一个线程正在访问一个进程对象时,另一个线程要改变该对象,这时可能会产生错误的结果。所以,程序员编程时要解决这种冲突。 最简单的避免线程冲突的的方法是使线程之间永远不与相同的数据或资源交互。但这不一定可行,对任何多线程程序来说,避免或最小化共享数据或资源应作为一个目标。 二、下面介绍一下在Win32 基础上用API函数进行多线程编程的过程。 1、用Win32函数创建和中止线程 Win32函数库中提供了多线程控制的操作函数,包括创建线程、中止线程、建立互斥区等。首先,在应用程序的主线程或者其它活动线程的适当地方创建新的线程。创建线程的函数如下:HANDLE CreateThread(LPSECURITY_A TTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); 其中,参数lpThreadAttributes 指定了线程的安全属性,在Windows 95中被忽略;dwStackSize 指定了线程的堆栈深度;lpStartAddress 指定了线程的起始地址,一般情况为下面的原型函数:DWORD WINAPI ThreadFunc( LPVOID );lpParameter指定了线程执行时传送给线程的32位参数,即上面函数的参数;dwCreationFlags指定了线程创建的特性;lpThreadId 指向一个DWORD 变量,可返回线程ID值。 如果创建成功则返回线程的句柄,否则返回NULL。 创建了新的线程后,则该线程就开始启动执行了。如果在dwCreationFlags中用了CREA TE_SUSPENDED特性,那么线程并不马上执行,而是先挂起,等到调用ResumeThread 后才开始启动线程,在这个过程中可以调用函数: BOOL SetThreadPriority( HANDLE hThread, int nPriority); 来设置线程的优先权。

相关主题
文本预览
相关文档 最新文档