实验2 线程同步机制
线程同步的方法有哪些
线程同步的方法有哪些线程同步是多线程编程中非常重要的一个概念,它是指多个线程在访问共享资源时,为了避免出现数据不一致或者冲突的情况,需要对线程进行协调和同步。
在实际的开发中,我们常常会遇到需要进行线程同步的情况,因此了解线程同步的方法是非常重要的。
本文将介绍几种常见的线程同步方法,希望能够帮助大家更好地理解和应用线程同步。
1. 互斥锁。
互斥锁是最常见的线程同步方法之一。
它通过对共享资源加锁的方式,保证同一时间只有一个线程可以访问该资源,其他线程需要等待锁的释放才能访问。
互斥锁可以使用操作系统提供的原子操作指令来实现,也可以使用编程语言提供的锁机制来实现,如Java中的synchronized关键字。
2. 信号量。
信号量是另一种常见的线程同步方法。
它可以用来控制对共享资源的访问权限,通过对信号量的值进行操作来实现线程的同步。
当信号量的值大于0时,表示资源可用,线程可以访问;当信号量的值等于0时,表示资源不可用,线程需要等待。
信号量的实现可以使用操作系统提供的信号量机制,也可以使用编程语言提供的信号量类来实现。
3. 条件变量。
条件变量是一种线程同步的高级方法,它可以用来在多个线程之间传递信息和控制线程的执行顺序。
条件变量通常和互斥锁一起使用,当共享资源的状态发生变化时,可以通过条件变量来通知等待的线程。
条件变量的实现通常需要依赖于操作系统提供的条件变量机制或者编程语言提供的条件变量类。
4. 读写锁。
读写锁是一种特殊的互斥锁,它可以提高对共享资源的并发访问性能。
读写锁允许多个线程同时对共享资源进行读操作,但是在进行写操作时需要互斥访问。
通过读写锁,可以有效地提高对共享资源的并发性能,适用于读操作频繁、写操作较少的场景。
5. 原子操作。
原子操作是一种特殊的指令序列,它可以保证在多线程环境下对共享资源的操作是原子性的,不会被中断。
原子操作通常由硬件提供支持,可以保证在执行过程中不会被其他线程打断,从而保证对共享资源的操作是线程安全的。
操作系统实验指导书(07)
《操作系统》——实验指导书编者:陈洺均桂林电子科技大学信息科技学院二00九年三月实验一Windows线程的创建与撤销一、实验目的1.熟悉Windows系统提供的线程创建与撤销系统调用。
2.掌握Windows系统环境下线程的创建与撤销方法。
二、实验预备内容(1)阅读Windows源码文件,加深对线程管理概念的理解;(2)CreateThread( )调用,创建一个线程;ExitThread ( )调用,撤销当前线程;TerminateThread( )终止线程;Sleep( )用于挂起当前正在执行的线程。
三、实验内容正确使用CreateThread()、ExitThread ( )及Sleep( )等系统调用,进一步理解进程与线程理论。
用系统调用CreateThread( )创建一个子线程,并在子线程序中显示:Thread is Runing!。
为了能让用户清楚地看到线程的运行情况,使用Sleep( )使线程挂起5S,之后使用ExitThread (0)撤销线程。
运行结果如下图所示:<参考程序 >// ThreadCreate.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include "ThreadCreate.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// The one and only application objectCWinApp theApp;using namespace std;void ThreadName1();static HANDLE hHandle1=NULL; //用于存储线程返回句柄的变量。
进程的同步与互斥实验报告
进程的同步与互斥实验报告1.实验目的进程(线程)的同步与互斥是操作系统中非常重要的概念,本实验旨在通过实际操作,加深对这些概念的理解和掌握。
通过编写多个进程(线程),并在其间进行同步与互斥操作,验证同步与互斥的实际效果。
2.实验环境本实验在Linux系统下进行,使用C/C++语言编程。
3.实验内容3.1同步在实验中,我们编写了两个进程A和B,这两个进程需要按照特定的顺序执行。
为了实现同步,我们使用信号量机制来确保进程A和B按照正确的顺序执行。
3.2互斥在实验中,我们编写了多个进程C和D,这些进程需要同时对一个共享资源进行访问。
为了实现互斥,我们使用互斥锁机制来确保同一时刻只有一个进程访问共享资源。
4.实验过程4.1同步实验编写进程A和进程B的代码,使用信号量机制实现同步。
进程A先运行,然后通过信号量唤醒进程B,进程B再开始执行。
通过观察进程的运行顺序,验证同步机制是否起作用。
4.2互斥实验编写进程C和进程D的代码,使用互斥锁机制实现互斥。
进程C和进程D同时对一个共享资源进行访问,通过互斥锁来确保同一时刻只有一个进程访问共享资源。
观察进程的输出结果,验证互斥机制是否起作用。
5.实验结果5.1同步实验结果进程A开始执行进程A执行完毕进程B开始执行进程B执行完毕5.2互斥实验结果进程C开始执行进程C访问共享资源进程C执行完毕进程D开始执行进程D访问共享资源进程D执行完毕6.实验分析通过上述结果可以看出,同步实验中进程A和进程B按照正确的顺序执行,证明了同步机制的有效性。
互斥实验中进程C和进程D能够正确地交替访问共享资源,证明了互斥机制的有效性。
7.实验总结通过本次实验,我深刻理解了进程(线程)的同步与互斥,并通过实际操作加深了对这些概念的理解。
同步和互斥是操作系统中非常重要的概念,对于应对资源竞争和提高程序性能具有重要意义。
在实际开发中,我们应该合理使用同步和互斥机制,以确保程序的正确性和并发执行的效率。
java多线程程序设计实验总结
java多线程程序设计实验总结一、实验目的本次实验旨在通过编写Java多线程程序,掌握多线程编程的基本概念和技能,理解多线程程序的运行原理,提高对Java语言的熟练度。
二、实验内容本次实验分为三个部分:创建线程、线程同步和死锁。
2.1 创建线程创建线程有两种方式:继承Thread类和实现Runnable接口。
继承Thread类需要重写run方法,在run方法中编写线程执行的代码;实现Runnable接口需要实现run方法,并将其作为参数传入Thread类的构造函数中。
在创建多个线程时,可以使用同一个Runnable对象或者不同的Runnable对象。
2.2 线程同步当多个线程同时访问共享资源时,可能会出现数据不一致等问题。
为了避免这种情况,需要使用同步机制来保证各个线程之间的协调运行。
常见的同步机制包括synchronized关键字和Lock接口。
synchronized关键字可以用来修饰方法或代码块,在执行该方法或代码块时,其他所有试图访问该方法或代码块的线程都必须等待当前执行完成后才能继续执行。
Lock接口提供了更加灵活和高级的锁机制,可以支持更多种类型的锁,如读写锁、可重入锁等。
2.3 死锁死锁是指两个或多个线程在互相等待对方释放资源的情况下,都无法继续执行的现象。
死锁的发生通常由于程序设计不当或者资源分配不合理所导致。
为避免死锁的发生,可以采取以下措施:避免嵌套锁、按照固定顺序获取锁、避免长时间占用资源等。
三、实验过程本次实验我编写了多个Java多线程程序,包括创建线程、线程同步和死锁。
其中,创建线程部分我使用了继承Thread类和实现Runnable 接口两种方式来创建线程,并测试了多个线程之间的并行执行情况;在线程同步部分,我使用synchronized关键字和Lock接口来保证共享资源的访问安全,并测试了多个线程同时访问共享资源时是否会出现数据不一致等问题;在死锁部分,我编写了一个简单的死锁程序,并通过调整程序代码来避免死锁的发生。
计算机操作系统实验二
计算机操作系统实验二一、实验目的本实验旨在通过实际操作,深入理解和掌握计算机操作系统中的进程与线程管理。
通过实验,我们将了解进程的创建、执行、阻塞、唤醒等状态以及线程的创建、同步、通信等操作。
同时,通过实验,我们将学习如何利用进程和线程提高程序的并发性和效率。
二、实验内容1、进程管理a.进程的创建与执行:通过编程语言(如C/C++)编写一个程序,创建一个新的进程并执行。
观察和记录进程的创建、执行过程。
b.进程的阻塞与唤醒:编写一个程序,使一个进程在执行过程中发生阻塞,并观察和记录阻塞状态。
然后,通过其他进程唤醒该进程,并观察和记录唤醒过程。
c.进程的状态转换:根据实际操作,理解和分析进程的状态转换(就绪状态、阻塞状态、执行状态)以及转换的条件和过程。
2、线程管理a.线程的创建与同步:编写一个多线程程序,创建多个线程并观察和记录线程的创建过程。
同时,使用同步机制(如互斥锁或信号量)实现线程间的同步操作。
b.线程的通信:通过消息队列或其他通信机制,实现多个线程间的通信。
观察和记录线程间的通信过程以及通信对程序执行的影响。
c.线程的状态转换:根据实际操作,理解和分析线程的状态转换(新建状态、就绪状态、阻塞状态、终止状态)以及转换的条件和过程。
三、实验步骤1、按照实验内容的要求,编写相应的程序代码。
2、编译并运行程序,观察程序的执行过程。
3、根据程序的输出和实际操作情况,分析和理解进程与线程的状态转换以及进程与线程管理的相关原理。
4、修改程序代码,尝试不同的操作方式,观察程序执行结果的变化,进一步深入理解和掌握进程与线程管理。
5、完成实验报告,总结实验过程和结果,提出问题和建议。
四、实验总结通过本次实验,我们深入了解了计算机操作系统中的进程与线程管理原理和实践操作。
在实验过程中,我们不仅学习了如何利用编程语言实现进程和线程的操作,还通过实际操作观察和分析了进程与线程的状态转换以及进程与线程管理的基本原理。
线程同步方法有哪些
线程同步方法有哪些
线程同步的常用方法有:
1. 使用锁:例如使用`Lock`类、`ReentrantLock`类或`synchronized`关键字来实现线程同步。
2. 使用条件变量:例如使用`Condition`类来控制线程等待和唤醒。
3. 使用信号量:例如使用`Semaphore`类来控制线程的并发数。
4. 使用栅栏:例如使用`CyclicBarrier`类来控制多个线程在某个点上同步。
5. 使用阻塞队列:例如使用`BlockingQueue`类来控制线程的顺序执行。
6. 使用计数器:例如使用`CountDownLatch`类来控制线程的等待和唤醒。
7. 使用原子类:例如使用`AtomicInteger`类来保证操作的原子性。
8. 使用同步容器:例如使用`ConcurrentHashMap`类来保证线程安全。
9. 使用线程池:例如使用`ExecutorService`类来调度线程的执行顺序。
10. 使用并发工具类:例如使用`ReadWriteLock`类来实现多线程对某个资源的读写操作。
程序并发执行实验报告
一、实验目的1. 理解并发执行的概念和原理。
2. 掌握多线程编程的基本方法。
3. 学会使用同步机制解决并发编程中的竞争条件。
4. 分析并发程序的性能和效率。
二、实验环境1. 操作系统:Windows 102. 编程语言:Java3. 开发工具:Eclipse三、实验内容1. 创建一个简单的并发程序,实现两个线程同时执行。
2. 使用同步机制解决并发程序中的竞争条件。
3. 分析并发程序的性能和效率。
四、实验步骤1. 创建一个简单的并发程序(1)创建一个名为ConcurrentTest的类,该类继承自Thread类。
(2)在ConcurrentTest类的run方法中,打印出当前线程的名字。
(3)在主函数中,创建两个ConcurrentTest对象,分别命名为thread1和thread2。
(4)启动thread1和thread2线程。
(5)等待thread1和thread2线程执行完毕。
2. 使用同步机制解决并发程序中的竞争条件(1)创建一个名为Counter的类,该类包含一个私有变量count和一个静态同步方法add。
(2)在add方法中,增加count变量的值。
(3)在主函数中,创建一个Counter对象counter。
(4)创建两个线程,分别调用counter对象的add方法。
(5)启动两个线程,并等待它们执行完毕。
3. 分析并发程序的性能和效率(1)在主函数中,记录两个线程开始执行的时间。
(2)在主函数中,记录两个线程执行完毕的时间。
(3)计算两个线程执行所需的时间差。
五、实验结果与分析1. 实验结果(1)简单的并发程序在控制台中,可以看到thread1和thread2线程交替打印出它们的名字。
(2)使用同步机制解决竞争条件在控制台中,可以看到Counter对象的count变量值正确地增加了。
(3)分析并发程序的性能和效率thread1和thread2线程执行所需的时间差为0.01秒。
2. 实验分析(1)简单的并发程序通过创建两个线程,实现了两个任务同时执行。
线程同步和互斥概念
线程同步和互斥概念在多线程编程中,线程同步和互斥是非常重要的概念。
线程同步指的是多个线程在执行过程中的协调和合作,以达到共同的目标。
而线程互斥则是指多个线程在访问共享资源时的互相排斥,以保证数据的一致性和正确性。
一、线程同步线程同步是指多个线程之间的协调和合作,以达到共同的目标。
在多线程编程中,线程同步可以通过各种机制来实现,例如锁、信号量、事件等。
1. 锁机制锁机制是最常见的线程同步机制之一。
锁机制可以保证在同一时间只有一个线程可以访问共享资源,其他线程需要等待锁的释放才能访问。
常见的锁有互斥锁、读写锁等。
例如,在一个多线程环境下,多个线程需要访问同一个全局变量,为了保证数据的一致性和正确性,可以使用互斥锁来实现线程同步。
2. 信号量机制信号量机制是另一种常见的线程同步机制。
信号量可以用来控制并发线程的数量,以达到线程同步的目的。
常见的信号量有二元信号量和计数信号量。
例如,在一个多线程环境下,多个线程需要访问同一个共享资源,为了保证数据的一致性和正确性,可以使用计数信号量来控制并发线程的数量。
3. 事件机制事件机制是一种高级的线程同步机制,可以用来实现线程之间的通信和协调。
事件机制通常包括事件对象、事件等待和事件通知等。
例如,在一个多线程环境下,多个线程需要协调完成一项任务,可以使用事件机制来实现线程同步。
二、线程互斥线程互斥是指多个线程在访问共享资源时的互相排斥,以保证数据的一致性和正确性。
在多线程编程中,线程互斥可以通过各种机制来实现,例如锁、信号量、事件等。
1. 锁机制锁机制可以用来实现线程互斥。
在同一时间只有一个线程可以获得锁,其他线程需要等待锁的释放才能访问共享资源。
例如,在一个多线程环境下,多个线程需要访问同一个全局变量,为了保证数据的一致性和正确性,可以使用互斥锁来实现线程互斥。
2. 信号量机制信号量机制也可以用来实现线程互斥。
通过设置信号量的初始值为1,可以保证只有一个线程可以访问共享资源。
创建线程的实验报告
一、实验目的1. 理解线程的概念和作用。
2. 掌握在Java中创建线程的方法。
3. 学习线程的生命周期和线程同步。
4. 熟悉线程的调度和同步机制。
二、实验环境1. 操作系统:Windows 102. 开发工具:IntelliJ IDEA3. 编程语言:Java三、实验内容1. 创建线程2. 线程生命周期3. 线程同步4. 线程调度四、实验步骤1. 创建线程(1)继承Thread类创建线程```javapublic class MyThread extends Thread { @Overridepublic void run() {// 线程要执行的任务System.out.println("子线程:" + Thread.currentThread().getName());}}```(2)实现Runnable接口创建线程```javapublic class MyRunnable implements Runnable {@Overridepublic void run() {// 线程要执行的任务System.out.println("子线程:" +Thread.currentThread().getName());}}```2. 线程生命周期线程生命周期包括以下五个状态:(1)新建(New):线程对象被创建后,处于此状态。
(2)就绪(Runnable):线程对象被创建后,调用start()方法,线程进入就绪状态。
(3)运行(Running):线程被调度到CPU上执行,处于运行状态。
(4)阻塞(Blocked):线程因为某些原因无法执行,进入阻塞状态。
(5)终止(Terminated):线程执行完毕或被强制终止,处于终止状态。
以下代码演示了线程的生命周期:```javapublic class LifeCycleDemo {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());System.out.println("线程状态:" + thread.getState());thread.start();System.out.println("线程状态:" + thread.getState());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程状态:" + thread.getState());}}```3. 线程同步线程同步是为了避免多个线程同时访问共享资源时出现冲突。
cuda的同步机制
CUDA的同步机制1. 引言CUDA(Compute Unified Device Architecture)是由英伟达(NVIDIA)推出的一种并行计算平台和编程模型。
它允许开发人员在GPU(Graphics Processing Unit,图形处理器)上进行高性能计算。
在CUDA编程中,同步机制是非常重要的,它可以确保并行计算中的各个线程在需要的时候进行同步,以避免数据竞争和不一致的结果。
本文将详细介绍CUDA的同步机制,包括线程同步、块同步和设备同步,以及它们的实现原理和使用方法。
2. 线程同步在CUDA中,每个线程都有自己的线程编号(thread ID),线程可以通过线程编号来访问不同的数据。
线程同步是指在并行计算中,多个线程之间需要相互协作,保证计算的正确性和一致性。
2.1. 线程同步的实现方法CUDA提供了多种线程同步的实现方法,包括互斥锁(mutex)、信号量(semaphore)和屏障(barrier)等。
•互斥锁:互斥锁是一种常用的线程同步机制,它可以确保在任意时刻只有一个线程可以访问共享资源。
CUDA中的互斥锁可以通过__syncthreads()函数来实现,具体的使用方法是在需要同步的地方调用__syncthreads()函数,以确保所有线程都执行到该点。
•信号量:信号量是一种用于多线程之间同步的机制,它可以控制多个线程的执行顺序。
CUDA中的信号量可以通过atomicAdd()函数来实现,具体的使用方法是将一个共享的变量作为信号量,通过原子加法操作来控制线程的执行顺序。
•屏障:屏障是一种同步机制,它可以确保在某个点之前的所有线程都执行完毕后再继续执行后续的代码。
CUDA中的屏障可以通过__syncthreads()函数来实现,具体的使用方法是在需要同步的地方调用__syncthreads()函数。
2.2. 线程同步的应用场景线程同步在CUDA编程中有着广泛的应用场景,例如:•数据的初始化:在并行计算中,多个线程可能同时访问同一个共享的数据结构,为了避免数据的竞争和不一致,需要使用线程同步来确保数据的正确初始化。
大学计算机实验报告答案
一、实验目的1. 理解操作系统基本概念和功能。
2. 掌握进程和线程的基本知识。
3. 学习进程调度和同步机制。
4. 熟悉操作系统实验环境。
二、实验环境1. 操作系统:Windows 102. 编程语言:C/C++3. 开发环境:Visual Studio 2019三、实验内容1. 进程和线程的创建与终止2. 进程调度算法(先来先服务、短作业优先、轮转)3. 线程同步机制(互斥锁、条件变量、信号量)四、实验步骤1. 进程和线程的创建与终止(1)创建进程使用函数`fork()`创建子进程,实现进程的创建。
```c#include <unistd.h>#include <stdio.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork error");return 1;} else if (pid == 0) {// 子进程printf("I am child process, PID: %d\n", getpid()); // 执行子进程任务} else {// 父进程printf("I am parent process, PID: %d\n", getpid()); // 等待子进程结束wait(NULL);}return 0;}```(2)创建线程使用函数`pthread_create()`创建线程,实现线程的创建。
```c#include <pthread.h>#include <stdio.h>void thread_func(void arg) {printf("Thread ID: %ld\n", pthread_self());return NULL;}int main() {pthread_t tid;if (pthread_create(&tid, NULL, thread_func, NULL) != 0) { perror("pthread_create error");return 1;}// 等待线程结束pthread_join(tid, NULL);return 0;}```(3)终止进程和线程使用函数`exit()`和`pthread_exit()`终止进程和线程。
线程同步和线程协作
多线程单例---饿汉模式
程序启动的时候,立马启动,拿空间换时间
不使用synchronize关键字,使用的是jvm中自带的锁
懒汉模式和饿汉模式的区别:
懒汉模式假如没有synchronize关键字,将会出现线程不安全,导致性能低。
饿汉模式在系统加载的时候,立刻加载,加载时太早
第四种:优化的懒汉模式(兼懒汉和饿汉两种特性)
性能:综合性能比较好。
4、线程协作
说明:线程协作,研究的是在特殊的情况下,对象监视器的释放问题。在对象监视块中释放对象监视器。
生产者,消费者----面试重点
缺点:效率低下。
2、事物管理
原子性,一致性,持久性,隔离性
隔离性:研究的就是线程同步,隔离数据---隔离表---隔离数据库
锁机制:
悲观锁:添加数据--->一张表被操作时,其他人不能对这张表进行操作。
乐观锁:用户添加数据的时候,允许他人查询,删除,
说明:面包店卖面包
1、两个消费者和两个生产者
2、一个面包柜中只能装10个面包,满了就不生产。
空了就不消费。
3、假如现在柜子中有9个面包,生产者一号发现没有满,去生产,一号在生产而没生产结束的时候,二号生产者发现柜子没有满-----出错
4、当柜子还有一个面包,消费者一号消费,二号消费者来了消费----出错
并发:同时存在多个进程处在启动、运行和结束之间,这些进程必须运行在同一个处理机上,导致出现资源不一致。
本质:研究线程和对象监视器之间的关系。
:每个对象都拥有一个class文件(class中有一个对象监视器)
synchronize:放了对象监视器,谁拿到监视器,谁先操作
生产者,消费者问题
实训二操作系统中的经典线程同步问题一、实训目的:1、通过对“生产者-消费者”问题编程实现,了解线程创建、同步信号量、互斥信号量、临界区的创建和使用。
2、了解线程互斥和同步机制。
3、了解PV 原语和信号量在线程互斥和同步机制中的运用。
二、实训环境:一台PC 机/人三、预习内容:1、进程的控制。
2、进程同步。
3、本实验内容主要对应于教材第 2 章中关于进程的各节四、实训内容:1、编写进程控制程序并运行,理解进程控制的各操作。
2、生产者和消费者问题,本实验用到几个API 函数:CreatThread, CreatMutex, CreatSemaphore, WaitForSingleObject, ReleaseSemaphore, ReleaseMutex, InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection这些函数的作用:CreatThread: 创建一个线程,该线程在调用进程的地址空间中执CreatMutex : 产生一个命名的或者匿名的互斥量对象。
WaitForSingleObject (对应p 操作)锁上互斥锁,ReleaseMutex (对应v 操作)打开互斥锁。
CreateSemaphore:创建一个命名的或者匿名的信号对象信号量可以看作是在互斥量上的一个扩展。
WaitForSingleObject :使程序处于等待状态,直到信号量(或互斥量)hHandle出现或者超过规定的等待最长时间,信号量出现指信号量大于或等于1,互斥量出现指打开互斥锁。
在返回之前将信号量减1或者锁上互斥锁。
Releasesemaphore将所指信号量加上指定大小的一个量,执行成功,则返回非0值。
ReleaseMutex :用来打开互斥量,即将互斥量加1。
成功调用则返回0。
InitializeCriticalSection :该函数初始化临界区对象。
synchronized简书
Synchronized是Java中用于实现线程同步的关键字,它可以保证多个线程在访问共享资源时的安全性。
在本文中,我们将通过以下内容探讨Synchronized的作用、原理和使用方法。
一、Synchronized的作用1.1 保证线程安全Synchronized可以确保在多线程环境下共享资源的安全访问。
当多个线程同时访问某个对象时,使用Synchronized可以避免出现数据竞争和并发访问的问题,从而保证程序的正确性和稳定性。
1.2 实现线程同步通过Synchronized关键字,可以实现线程之间的同步操作,使得多个线程按照既定的顺序执行,避免因为线程间的情况而导致程序逻辑混乱和错误。
二、Synchronized的原理2.1 对象锁和类锁Synchronized实现线程同步的原理是基于对象锁和类锁的机制。
当多个线程同时访问一个对象时,只有持有该对象的锁的线程才能进入临界区,其他线程将被阻塞。
同样,类锁也具有类似的作用,能够保证类级别的线程同步。
2.2 保证可见性和原子性Synchronized还能够保证共享变量的可见性和原子性。
当一个线程对共享变量进行修改时,Synchronized会将该线程对共享变量进行的修改立即刷入主存,从而保证其他线程能够看到最新的值;Synchronized还能够保证共享变量的修改操作是原子性的,不会被打断。
三、Synchronized的使用方法3.1 在方法中使用Synchronized可以在方法的定义中使用Synchronized关键字,以保护整个方法体中的共享资源,从而确保线程安全和同步操作。
3.2 在代码块中使用Synchronized除了在方法中使用Synchronized外,还可以在代码块中使用Synchronized来保护临界区,限制多个线程对共享资源的访问。
3.3 使用Synchronized修饰静态方法Synchronized还可以修饰静态方法,实现对类级别的线程同步,确保多个线程对静态方法的安全访问。
同步机制实验报告
一、实验目的1. 理解同步机制的基本概念和原理;2. 掌握不同同步机制(如互斥锁、条件变量、信号量等)的使用方法;3. 通过实验验证同步机制在解决并发编程中的同步和互斥问题。
二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发工具:Visual Studio 2019三、实验内容本次实验主要涉及以下同步机制:1. 互斥锁(Mutex)2. 条件变量(Condition Variable)3. 信号量(Semaphore)1. 互斥锁(Mutex)(1)实验目的:验证互斥锁在解决临界区访问冲突问题中的作用。
(2)实验步骤:1)定义互斥锁对象;2)创建多个线程,每个线程尝试访问临界区;3)在访问临界区之前,使用互斥锁进行加锁和解锁操作。
(3)实验结果:实验结果显示,在多个线程访问临界区时,互斥锁成功避免了冲突,确保了临界区的安全访问。
2. 条件变量(Condition Variable)(1)实验目的:验证条件变量在解决生产者-消费者问题中的作用。
(2)实验步骤:1)定义条件变量对象和互斥锁对象;2)创建生产者线程和消费者线程;3)生产者在生产数据时,使用条件变量通知消费者;4)消费者在消费数据时,使用条件变量等待生产者通知。
(3)实验结果:实验结果显示,在多个生产者和消费者线程并发执行时,条件变量成功实现了生产者和消费者之间的同步,避免了生产者和消费者之间的冲突。
3. 信号量(Semaphore)(1)实验目的:验证信号量在解决线程同步问题中的作用。
(2)实验步骤:1)定义信号量对象;2)创建多个线程,每个线程在执行任务前,需要等待信号量释放;3)在任务完成后,释放信号量,以便其他线程执行。
(3)实验结果:实验结果显示,在多个线程并发执行时,信号量成功实现了线程之间的同步,确保了线程按照预期顺序执行。
四、实验总结通过本次实验,我们深入了解了同步机制的基本概念和原理,掌握了互斥锁、条件变量和信号量等同步机制的使用方法。
实验2 线程同步机制
实验2 线程同步机制一、实验目的:通过观察共享数据资源但不受控制的两个线程的并发运行输出结果,体会同步机制的必要性和重要性。
然后利用现有操作系统提供的同步机制编程实现关于该两个线程的有序控制,同时要求根据同步机制的Peterson软件解决方案尝试自己编程实现同步机制和用于同一问题的解决,并基于程序运行时间长短比较两种同步机制。
二、实验设计I基于给定银行账户间转账操作模拟代码作为线程执行代码,在主线程中创建两个并发线程,编程实现并观察程序运行结果和予以解释说明。
II利用Windows互斥信号量操作函数解决上述线程并发问题,并分析、尝试和讨论线程执行体中有关信号量操作函数调用的正确位置。
III根据同步机制的Peterson软件解决方案尝试自己编程实现线程同步机制和用于上述线程并发问题的解决,并基于程序运行时间长短将其与基于Windows互斥信号量的线程同步机制的效率展开比较。
其间,可规定线程主体代码循环执行1000000次三、源程序清单和说明1未利用互斥信号量#include <windows.h>#include <stdlib.h>#include <stdio.h>int nAccount1 = 0, nAccount2 = 0;int nLoop = 0;int nTemp1, nTemp2, nRandom;DWORD WINAPI ThreadFunc<HANDLE Thread>{do{nTemp1 = nAccount1;nTemp2 = nAccount2;nRandom = rand<>;nAccount1 = nTemp1 + nRandom;nAccount2 = nTemp2 - nRandom;nLoop++;} while <<nAccount1 + nAccount2> == 0>;printf<"循环次数为%d\n", nLoop>;return 0;}int main<>{HANDLE Thread[2];Thread[0] = CreateThread<NULL,0,ThreadFunc,NULL,0,NULL>;Thread[1] = CreateThread<NULL,0,ThreadFunc,NULL,0,NULL>;WaitForMultipleObjects<2,Thread,TRUE,INFINITE>;CloseHandle<Thread>;return 0;}2利用Windows互斥信号量#include <windows.h>#include <stdlib.h>#include <stdio.h>#define COUNT 1000000int nAccount1 = 0, nAccount2 = 0;HANDLE mutex;DWORD WINAPI ThreadFunc<HANDLE Thread>{int nLoop = 0;int nTemp1, nTemp2, nRandom;WaitForSingleObject<mutex,INFINITE>;do{nTemp1 = nAccount1;nTemp2 = nAccount2;nRandom = rand<>;nAccount1 = nTemp1 + nRandom;nAccount2 = nTemp2 - nRandom;nLoop++;ReleaseMutex<mutex>;WaitForSingleObject<mutex,INFINITE>;}while <<nAccount1 + nAccount2> == 0&&nLoop < COUNT>;ReleaseMutex<mutex>;WaitForSingleObject<mutex,INFINITE>;printf<"循环次数为%d\n", nLoop>;ReleaseMutex<mutex>;return 0;}int main<>{HANDLE Thread[2];DWORD start, end;start = GetTickCount<>;mutex = CreateMutex<NULL,FALSE,NULL>;Thread[0] = CreateThread<NULL,0,ThreadFunc,NULL,0,NULL>;Thread[1] = CreateThread<NULL,0,ThreadFunc,NULL,0,NULL>;WaitForMultipleObjects<2,Thread,TRUE,INFINITE>;end = GetTickCount<>;printf<"总共用时%ld\n",end-start>;CloseHandle<Thread>;CloseHandle<mutex>;return 0;}3同步机制的Peterson#include <windows.h>#include <stdlib.h>#include <stdio.h>#define COUNT 1000000int nAccount1 = 0, nAccount2 = 0, flag[2], turn;int nLoop = 0;int nTemp1, nTemp2, nRandom;//HANDLE mutex;void request < int id >{int other = 1 - id;flag[id] = 1;turn = other;while < flag[other] == 1 && turn == other >{};}DWORD WINAPI ThreadFunc0<HANDLE Thread>{request<0>;do{nTemp1 = nAccount1;nTemp2 = nAccount2;nRandom = rand<>;nAccount1 = nTemp1 + nRandom;nAccount2 = nTemp2 - nRandom;nLoop++;flag[0] = 0;request<0>;}while <<nAccount1 + nAccount2> == 0 && nLoop < COUNT>; flag[0] = 0;request<0>;flag[0] = 0;printf<"循环次数为%d\n", nLoop>;return 0;}DWORD WINAPI ThreadFunc1<HANDLE Thread>{request<1>;do{nTemp1 = nAccount1;nTemp2 = nAccount2;nRandom = rand<>;nAccount1 = nTemp1 + nRandom;nAccount2 = nTemp2 - nRandom;nLoop++;flag[1] = 0;request<1>;}while <<nAccount1 + nAccount2> == 0 && nLoop < COUNT>; flag[1] = 0;request<1>;flag[1] = 0;printf<"循环次数为%d\n", nLoop>;return 0;}int main<>{HANDLE Thread[2];DWORD start, end;start = GetTickCount<>;Thread[0] = CreateThread<NULL,0,ThreadFunc0,NULL,0,NULL>;Thread[1] = CreateThread<NULL,0,ThreadFunc1,NULL,0,NULL>;WaitForMultipleObjects<2,Thread,TRUE,INFINITE>;end = GetTickCount<>;printf<"总共用时%ld\n",end-start>;CloseHandle<Thread>;return 0;}四、算法及关键数据结构设计1.银行账户间转账操作模拟int nAccount1 = 0, nAccount2 = 0; //主线程创建的全局变量int nLoop = 0;int nTemp1, nTemp2, nRandom;do{nTemp1 = nAccount1;nTemp2 = nAccount2;nRandom = rand<>;nAccount1 = nTemp1 + nRandom;nAccount2 = nTemp2 - nRandom;nLoop++;} while <<nAccount1 + nAccount2> = = 0>;printf<"循环次数为%d\n", nLoop>;2.进程互斥算法1−设置访问编号Var turn: integer :=i;repeat……while turn≠i do no_op;临界区turn:=j;……until false;3.进程互斥算法2−设置访问标志Var flag i, flag j: boolean :=false, false;repeatwhile flag j do no_op;flag i := true;临界区flag i := false;until false;4.进程互斥算法3−设置访问标志Var flag i, flag j: boolean :=false, false;repeatflag i := true;while flag j do no_op;临界区flag i := false;until false;5.进程互斥算法4−编号+标志Var flag i, flag j: boolean;turn: integer;repeatflag i := true; turn := j;while <flag j and turn=j> do no_op;临界区flag i := false;until false;五、实验过程中间结果屏幕截图实验结果1未利用互斥信号量2利用Windows互斥信号量3同步机制的Peterson结果分析1没有应用互斥信号量对线程进行并发控制,运行会产生错误。
实验二_生产者消费者问题
实验二生产者-消费者同步问题班级: B08516 姓名:王益鑫学号 13 日期: 2010-10-191.实验目的(1)全面理解生产者与消费者问题模型,掌握解决该问题的算法思想,正确使用同步机制。
(2)学习使用Linux线程同步机制解决互斥和同步问题。
2.实验环境已安装Linux操作系统的微机一台3.实验内容问题描述:一组生产者向一组消费者提供消息,它们共享一个有界缓冲池,生产者向其中投放消息,消费者从中取得消息。
假定这些生产者和消费者互相等效,只要缓冲池未满,生产者可将消息送入缓冲池;只要缓冲池未空,消费者可从缓冲池取走一个消息。
功能要求:根据进程同步机制,编写一个解决上述问题的程序,可显示缓冲池状态、放数据、取数据等过程。
4.具体设计要求及有关说明(1)有2个生产者线程,分别为P1、P2;有2个消费者进程,分别是C1、C2;缓冲区单元个数N=15;(2)不同的生产者可生产不同的产品(比如字母、数字、符号);不同的消费者可有不同的消费方式(比如“显示”、“打印”、“拼接成字符串”、“改变大小写”等)。
自己可任意定义。
(3)使用Linux线程同步:mutex、condition virable和semaphore完成上述问题。
(4)程序源代码和实验结果如下:#include <>#include <>#include <>sem_t blank_number, product_number;pthread_cond_t full = PTHREAD_COND_INITIALIZER;pthread_cond_t empty = PTHREAD_COND_INITIALIZER;pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;#define NUM 15struct P_Queue {char productc[NUM];int front, rear;int num;};void *producer1(void *arg){ struct P_Queue *q;q = (struct P_Queue *) arg;while (1) {pthread_mutex_lock(&lock);while (q->num == NUM) {pthread_cond_wait(&full, &lock);}sem_wait(&blank_number);char c = rand() % 26 + 'a';q->rear = (q->rear + 1) % NUM;q->productc[q->rear] = c;printf("缓冲池1的产品是:%c\n", q->productc[q->rear]); q->num++;printf("产品数量:%d\n", q->num);sem_post(&product_number);if (q->num == 1) {pthread_cond_signal(&empty);}pthread_mutex_unlock(&lock);sleep(rand() % 2);}}void *producer2(void *arg){struct P_Queue *q;q = (struct P_Queue *) arg;while (1) {pthread_mutex_lock(&lock);while (q->num == NUM) {pthread_cond_wait(&full, &lock);}sem_wait(&blank_number);char c = rand() % 26 + 'A';q->rear = (q->rear + 1) % NUM;q->productc[q->rear] = c;printf("缓冲池2的产品是:%c\n", q->productc[q->rear]); q->num++;printf("产品数量:%d\n", q->num);sem_post(&product_number);if (q->num == 1) {pthread_cond_signal(&empty);}pthread_mutex_unlock(&lock);sleep(rand() % 2);}}void *consumer1(void *arg){struct P_Queue *q;q = (struct P_Queue *) arg;while (1) {pthread_mutex_lock(&lock);while (q->num == 0) {pthread_cond_wait(&empty, &lock); }sem_wait(&product_number);q->front = (q->front + 1) % NUM;char c = q->productc[q->front];q->productc[q->front] = ' ';q->num--;printf("消费者1显示内容: %c\n", c); printf("产品数量:%d\n", q->num);sem_post(&blank_number);if (q->num == NUM - 1) {pthread_cond_signal(&full);}pthread_mutex_unlock(&lock);sleep(rand() % 2);}}void *consumer2(void *arg){struct P_Queue *q;q = (struct P_Queue *) arg;while (1) {pthread_mutex_lock(&lock);while (q->num == 0) {pthread_cond_wait(&empty, &lock); }sem_wait(&product_number);q->front = (q->front + 1) % NUM;char c = q->productc[q->front];char d = 0;if(c>=65 && c<=90){ d = c+32;}else{ d = c-32;}q->productc[q->front] = ' ';q->num--;printf("消费者2更改大小写:%c---%c\n", c,d);printf("产品数量:%d\n", q->num);sem_post(&blank_number);if (q->num == NUM - 1) {pthread_cond_signal(&full);}pthread_mutex_unlock(&lock);sleep(rand() % 2);}}int main(int argc, char *argv[]){struct P_Queue *q;q = (struct P_Queue *) malloc(sizeof(struct P_Queue)); q->front = q->rear = NUM - 1;q->num = 0;pthread_t pid1, cid1, pid2, cid2;sem_init(&blank_number, 0, NUM);sem_init(&product_number, 0, 0);pthread_create(&pid1, NULL, producer1, (void *) q);pthread_create(&cid1, NULL, consumer1, (void *) q);pthread_create(&pid2, NULL, producer2, (void *) q);pthread_create(&cid2, NULL, consumer2, (void *) q);pthread_join(pid1, NULL);pthread_join(cid1, NULL);pthread_join(pid2, NULL);pthread_join(cid2, NULL);sem_destroy(&blank_number);sem_destroy(&product_number);}程序运行结果如下:图1-1 运行结果5.实验总结1.写出Linux系统中线程同步实现机制有哪些怎样使用Linux系统中线程同步实现机制通过对互斥变量Mutex、信号灯Semophore、条件变量Conditions的设置实现线程的同步。
进程线程同步的方式和机制,进程间通信
进程/线程同步的方式和机制,进程间通信一、进程/线程间同步机制。
临界区、互斥区、事件、信号量四种方式临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)的区别1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。
在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。
2、互斥量:采用互斥对象机制。
只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。
互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享 .互斥量比临界区复杂。
因为使用互斥不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享。
3、信号量:它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目 .信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中的PV操作相同。
它指出了同时访问共享资源的线程最大数目。
它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。
PV操作及信号量的概念都是由荷兰科学家E.W.Dijkstra提出的。
信号量S是一个整数,S大于等于零时代表可供并发进程使用的资源实体数,但S小于零时则表示正在等待使用共享资源的进程数。
P操作申请资源:(1)S减1;(2)若S减1后仍大于等于零,则进程继续执行;(3)若S减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转入进程调度。
V操作释放资源:(1)S加1;(2)若相加结果大于零,则进程继续执行;(3)若相加结果小于等于零,则从该信号的等待队列中唤醒一个等待进程,然后再返回原进程继续执行或转入进程调度。
线程的同步和互斥问题
实验二线程的同步和互斥问题一.实验内容:编写程序实现并发线程之间的同步和互斥问题。
线程间的互斥:并发执行的线程共享某些类临界资源,对临界资源的访问应当采取互斥的机制。
线程间的同步:并发执行的线程间通常存在相互制约的关系,线程必须遵循一定的规则来执行,同步机制可以协调相互制约的关系。
二.实验目的和要求1)了解进程同步与互斥的概念,掌握编写进程同步、互斥的实例。
2)解决一类典型的进程间同步问题,如生产者-消费者问题,读者-写者问题等。
三.实验方法和步骤1.实验方法掌握同步与互斥的机制,选取合适的问题,给出演示程序的设计思想,包括流程图的形式;选取C、C++、VC、JA V A等计算机语言,编程调试,最终给出运行正确的程序。
2.程序设计(1)线程间互斥:分析问题,创建多个线程,找出临界资源,划出正确的临界区,根据互斥机制的操作模式,编写程序。
互斥机制的操作模式:p(mutex);/*关锁*/临界区的操作;v(mutex);/*开锁*/(2)线程间同步——读者-写者问题示例:在Windows 2000 环境下,创建一个包含n 个线程的控制台进程。
用这n 个线程来表示n个读者或写者。
每个线程按相应测试数据文件的要求,进行读写操作。
请用信号量机制分别实现读者优先和写者优先的读者-写者问题。
读者-写者问题的读写操作限制:1)写-写互斥;2)读-写互斥;3)读-读允许;运行结果显示要求:要求在每个线程创建、发出读写操作申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确信所有处理都遵守相应的读写操作限制。
测试数据文件格式测试数据文件包括n 行测试数据,分别描述创建的n 个线程是读者还是写者,以及读写操作的开始时间和持续时间。
每行测试数据包括四个字段,各字段间用空格分隔。
第一字段为一个正整数,表示线程序号。
第二字段表示相应线程角色,R 表示读者是,W 表示写者。
第三字段为一个正数,表示读写操作的开始时间。
线程同步的几种实现方案
线程同步的⼏种实现⽅案当多个线程对同⼀数据进⾏访问时,容易出现线程安全问题,这个时候就需要让线程同步来保证数据的安全。
线程同步就是说在两个或两个以上的线程访问同⼀资源的时候,需要⽤到某种⽅式来保证资源在某⼀时刻只能被⼀个线程访问线程同步的实现⽅案:⼀、同步代码块:synchronized(同步监视器) 1、认识同步监视器(锁⼦) synchronized(同步监视器){} 1)必须是引⽤数据类型,不能是基本数据类型 2)在同步代码块中可以改变同步监视器对象的值,不能改变其引⽤ 3)尽量不要使⽤String和包装类Integer做同步监视器,如果要使⽤,则必须保证代码快啊中不对其做任何操作 4)⼀般使⽤共享资源做同步器 5)可以创建⼀个专门的同步监视器,没有任何含义 6)建议使⽤final来修饰同步监视器 2、同步代码块的执⾏过程 1)第⼀个线程来到同步代码块,发现同步监视器是open状态,需要close,然后执⾏其中的代码 2)第⼀个线程执⾏过程中,发⽣了线程切换(阻塞就绪),第⼀个线程失去了CPU,但是没有开锁 3)第⼆个线程获取了CPU,来到同步代码块,发现同步监视器close状态,⽆法执⾏其中的代码,第⼆个也进⼊了阻塞状态 4)第⼀个线程再次获得CPU,执⾏后续代码,执⾏完毕释放锁 5)第⼆个线程再次获得CPU,来到同步代码块发现是开锁状态,重复第⼀个线程的处理过程 3、下⾯的代码是⽤同步代码块来实现线程同步(多个窗⼝实现安全售票)public class TiketsTest {public static void main(String[] args) {for(int i = 0;i<5;i++){//运⽤循环来开启五个线程(模拟五个售票员)new Thread(new TiketsRunnable(),"售票员"+(i+1)).start();//此处为了⽅便直接使⽤匿名对象}}public class TiketsRunnable implements Runnable {private int tikets = 100;//要卖票的总数private Object obj = new Object();@Overridepublic void run() {while (true){synchronized (obj) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}if (tikets <= 0) {break;}System.out.println(Thread.currentThread().getName() + "卖了第" + tikets-- + "票");}}}}⼆、同步⽅法:修饰符 synchronized 返回值类型⽅法名(参数){} 1、不要将run()定义为同步⽅法 2、同步⽅法的同步监视器是this 3、同步代码块的效率要⾼于同步⽅法 1)同步⽅法的锁是this,⼀旦锁住⼀个⽅法,就锁住了所有的同步⽅法;同步代码块只是锁住了使⽤该同步代码块,⽽没有锁住使⽤其他监视器的代码块 2)同步⽅法是将线程锁在了⽅法的外部,⽽同步代码块将线程锁在了代码块的外部,但是却是⽅法的内部 4、下⾯的代码是⽤同步⽅法来实现线程同步(多个窗⼝实现安全售票)public class TiketsTest {public static void main(String[] args) {for(int i = 0;i<5;i++){//运⽤循环来开启五个线程(模拟五个售票员)new Thread(new TiketsRunnable(),"售票员"+(i+1)).start();//此处为了⽅便直接使⽤匿名对象}}}public class TiketsRunnable implements Runnable {private int tikets = 3;private Object obj = new Object();@Overridepublic void run() {while (true) {sell();if (tikets <= 0) {break;}}}public synchronized void sell(){//同步⽅法if(tikets<=0){return;}try {Thread.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "卖了第" + tikets+ "票");tikets --;}}三、Lock锁 1、Lock锁 1)JDK1.5后新增功能,与采⽤synchronized想⽐,lock锁可提供多种锁⽅案,更灵活 2)java.util.concurrent.lock 中的 Lock 框架是锁定的⼀个抽象,它允许把锁定的实现作为 Java 类,⽽不是作为语⾔的特性来实现。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验2 线程同步机制一、实验目的:通过观察共享数据资源但不受控制的两个线程的并发运行输出结果,体会同步机制的必要性和重要性。
然后利用现有操作系统提供的同步机制编程实现关于该两个线程的有序控制,同时要求根据同步机制的Peterson软件解决方案尝试自己编程实现同步机制和用于同一问题的解决,并基于程序运行时间长短比较两种同步机制。
二、实验设计I基于给定银行账户间转账操作模拟代码作为线程执行代码,在主线程中创建两个并发线程,编程实现并观察程序运行结果和予以解释说明。
II利用Windows互斥信号量操作函数解决上述线程并发问题,并分析、尝试和讨论线程执行体中有关信号量操作函数调用的正确位置。
III根据同步机制的Peterson软件解决方案尝试自己编程实现线程同步机制和用于上述线程并发问题的解决,并基于程序运行时间长短将其与基于Windows互斥信号量的线程同步机制的效率展开比较。
其间,可规定线程主体代码循环执行1000000次三、源程序清单和说明1未利用互斥信号量#include <windows.h>#include <stdlib.h>#include <stdio.h>int nAccount1 = 0, nAccount2 = 0;int nLoop = 0;int nTemp1, nTemp2, nRandom;DWORD WINAPI ThreadFunc(HANDLE Thread){do{nTemp1 = nAccount1;nTemp2 = nAccount2;nRandom = rand();nAccount1 = nTemp1 + nRandom;nAccount2 = nTemp2 - nRandom;nLoop++;} while ((nAccount1 + nAccount2) == 0);printf("循环次数为%d\n", nLoop);return 0;}int main(){HANDLE Thread[2];Thread[0] = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);Thread[1] = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);WaitForMultipleObjects(2,Thread,TRUE,INFINITE);CloseHandle(Thread);return 0;}2利用Windows互斥信号量#include <windows.h>#include <stdlib.h>#include <stdio.h>#define COUNT 1000000int nAccount1 = 0, nAccount2 = 0;HANDLE mutex;DWORD WINAPI ThreadFunc(HANDLE Thread){int nLoop = 0;int nTemp1, nTemp2, nRandom;WaitForSingleObject(mutex,INFINITE);do{nTemp1 = nAccount1;nTemp2 = nAccount2;nRandom = rand();nAccount1 = nTemp1 + nRandom;nAccount2 = nTemp2 - nRandom;nLoop++;ReleaseMutex(mutex);WaitForSingleObject(mutex,INFINITE);}while ((nAccount1 + nAccount2) == 0&&nLoop < COUNT);ReleaseMutex(mutex);WaitForSingleObject(mutex,INFINITE);printf("循环次数为%d\n", nLoop);ReleaseMutex(mutex);return 0;}int main(){HANDLE Thread[2];DWORD start, end;start = GetTickCount();mutex = CreateMutex(NULL,FALSE,NULL);Thread[0] = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);Thread[1] = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);WaitForMultipleObjects(2,Thread,TRUE,INFINITE);end = GetTickCount();printf("总共用时%ld\n",end-start);CloseHandle(Thread);CloseHandle(mutex);return 0;}3同步机制的Peterson#include <windows.h>#include <stdlib.h>#include <stdio.h>#define COUNT 1000000int nAccount1 = 0, nAccount2 = 0, flag[2], turn;int nLoop = 0;int nTemp1, nTemp2, nRandom;//HANDLE mutex;void request ( int id ){int other = 1 - id;flag[id] = 1;turn = other;while ( flag[other] == 1 && turn == other ){};}DWORD WINAPI ThreadFunc0(HANDLE Thread){request(0);do{nTemp1 = nAccount1;nTemp2 = nAccount2;nRandom = rand();nAccount1 = nTemp1 + nRandom;nAccount2 = nTemp2 - nRandom;nLoop++;flag[0] = 0;request(0);}while ((nAccount1 + nAccount2) == 0 && nLoop < COUNT);flag[0] = 0;request(0);flag[0] = 0;printf("循环次数为%d\n", nLoop);return 0;}DWORD WINAPI ThreadFunc1(HANDLE Thread){request(1);do{nTemp1 = nAccount1;nTemp2 = nAccount2;nRandom = rand();nAccount1 = nTemp1 + nRandom;nAccount2 = nTemp2 - nRandom;nLoop++;flag[1] = 0;request(1);}while ((nAccount1 + nAccount2) == 0 && nLoop < COUNT);flag[1] = 0;request(1);flag[1] = 0;printf("循环次数为%d\n", nLoop);return 0;}int main(){HANDLE Thread[2];DWORD start, end;start = GetTickCount();Thread[0] = CreateThread(NULL,0,ThreadFunc0,NULL,0,NULL);Thread[1] = CreateThread(NULL,0,ThreadFunc1,NULL,0,NULL);WaitForMultipleObjects(2,Thread,TRUE,INFINITE);end = GetTickCount();printf("总共用时%ld\n",end-start);CloseHandle(Thread);return 0;}四、算法及关键数据结构设计1.银行账户间转账操作模拟int nAccount1 = 0, nAccount2 = 0; //主线程创建的全局变量int nLoop = 0;int nTemp1, nTemp2, nRandom;do{nTemp1 = nAccount1;nTemp2 = nAccount2;nRandom = rand();nAccount1 = nTemp1 + nRandom;nAccount2 = nTemp2 - nRandom;nLoop++;} while ((nAccount1 + nAccount2) = = 0);printf("循环次数为%d\n", nLoop);2.进程互斥算法1−设置访问编号Var turn: integer :=i;repeat……while turn≠i do no_op;临界区turn:=j;……until false;3.进程互斥算法2−设置访问标志Var flag i, flag j: boolean :=false, false;repeatwhile flag j do no_op;flag i := true;临界区flag i := false;until false;4.进程互斥算法3−设置访问标志Var flag i, flag j: boolean :=false, false;repeatflag i := true;while flag j do no_op;临界区flag i := false;until false;5.进程互斥算法4 编号+标志Var flag i, flag j: boolean;turn: integer;repeatflag i := true; turn := j;while (flag j and turn=j) do no_op;临界区flag i := false;until false;五、实验过程中间结果屏幕截图实验结果1未利用互斥信号量2利用Windows互斥信号量3同步机制的Peterson结果分析1没有应用互斥信号量对线程进行并发控制,运行会产生错误。
2利用Windows互斥信号量后,两存取款线程可并发正确执行。
成功转账100000次。
但加大了系统的时间开销。
时间效率低。
3应用同步机制的Peterson算法后,两线程也可顺利的并发执行,成功转账100000次,但相对于Windows互斥信号量,时间明显缩短。