进程并发执行的特性及其实现机制
目录
进程并发执行的背景
并发执行的特性
间断性
失去封闭性
不可再现性
并发执行的实例解析
示例1:资源共享的制约关系
示例2:公共变量的并发执行结果
常见问题与解答
并发执行的代码实现
1. 进程并发执行的背景
在计算机操作系统中,程序的顺序执行具有顺序性、封闭性和可再现性。然而,随着计算机性能的提升和多任务需求的增加,顺序执行的资源利用率较低,无法满足现代计算的需求。为了解决这一问题,操作系统引入了并发执行的概念。并发执行允许多个程序或进程同时运行,通过资源共享和任务协作,提高资源利用率和系统性能。
2. 并发执行的特性
2.1 间断性
在多道程序设计环境下,程序的并发执行可能会受到系统资源的制约。例如,多个进程共享CPU、内存和外设时,由于资源的使用时间不同,进程之间可能会出现相互制约的关系。这种制约关系导致程序的执行过程不再连续,而是呈现出间断性。
实例解析:
假设系统中有两个作业:作业1和作业2。作业1的执行顺序为输入(I1)、计算(C1)和输出(P1),作业2的执行顺序为输入(I2)、计算(C2)和输出(P2)。在并发执行时,作业1的计算(C1)和作业2的输入(I2)可以同时进行,从而提高资源利用率。
时间线:
0s - 作业1执行I1
1s - 作业2执行I2
2s - 作业1执行C1
3s - 作业2执行C2
4s - 作业1执行P1
5s - 作业2执行P2
2.2 失去封闭性
在顺序执行中,程序的运行结果仅与初始条件相关,与执行顺序和环境无关。然而,在并发执行中,多个程序共享系统资源,程序的运行结果不仅取决于初始条件,还受到执行顺序和环境的影响。因此,程序的运行结果失去了封闭性。
实例解析:
假设系统中有两个程序段S1和S2,它们的执行结果需要提交给程序段S3。如果S1和S2并发执行,S3的运行结果将依赖于S1和S2的执行顺序。
S3的输入条件:
S1完成 -> 提交结果给S3
S2完成 -> 提交结果给S3
S3运行 -> 依赖S1和S2的结果
2.3 不可再现性
在并发执行中,即使初始条件相同,程序的运行结果也可能不同。这种现象被称为不可再现性。不可再现性主要是由于程序的执行顺序和资源共享的不确定性导致的。
实例解析:
假设程序A和程序B共享一个公共变量N。程序A将N加1,程序B将N置为0。如果程序A和程序B的执行顺序不同,N的最终值也会不同。
// 程序A
int N = 0;
N = N + 1;
printf("%d", N); // 输出1
// 程序B
int N = 0;
printf("%d", N); // 输出0
N = 0;
3. 并发执行的实例解析
示例1:资源共享的制约关系
在并发执行中,多个进程共享系统资源时,可能会出现资源竞争和制约关系。例如,假设系统中有两个作业:作业1和作业2。作业1需要使用CPU和内存,作业2需要使用CPU和外设。如果作业1和作业2并发执行,可能会出现资源竞争。
时间线:
0s - 作业1使用CPU
1s - 作业2使用外设
2s - 作业1使用内存
3s - 作业2使用CPU
示例2:公共变量的并发执行结果
在并发执行中,多个进程共享公共变量时,可能会导致不可再现性。例如,假设程序A和程序B共享一个公共变量N。程序A将N加1,程序B将N置为0。如果程序A和程序B的执行顺序不同,N的最终值也会不同。
// 程序A
int N = 0;
N = N + 1;
printf("%d", N); // 输出1
// 程序B
int N = 0;
printf("%d", N); // 输出0
N = 0;
4. 常见问题与解答
以下是一些关于进程并发执行的常见问题及解答:
问题 答案
什么是并发执行? 并发执行允许多个程序或进程同时运行,通过资源共享和任务协作,提高资源利用率和系统性能。
并发执行有哪些特性? 并发执行具有间断性、失去封闭性和不可再现性。
为什么并发执行会导致不可再现性? 并发执行中,程序的执行顺序和资源共享的不确定性可能导致不可再现性。
如何解决并发执行中的资源竞争问题? 通过引入进程同步机制,如信号量和互斥锁,可以解决资源竞争问题。
并发执行对系统性能有哪些影响? 并发执行可以提高资源利用率和系统性能,但也可能导致不可再现性和资源竞争问题。
5. 并发执行的代码实现
以下是一些关于并发执行的代码实现:
示例1:多线程并发执行
import threading
def task1():
print("Task 1 started")
print("Task 1 completed")
def task2():
print("Task 2 started")
print("Task 2 completed")
# 创建线程
thread1 = threading.Thread(target=task1)
thread2 = threading.Thread(target=task2)
# 启动线程
thread1.start()
thread2.start()
# 等待线程完成
thread1.join()
thread2.join()
示例2:进程间通信
from multiprocessing import Process, Queue
def sender(queue):
queue.put("Hello from sender")
def receiver(queue):
message = queue.get()
print(f"Received: {message}")
# 创建队列
queue = Queue()
# 创建进程
process1 = Process(target=sender, args=(queue,))
process2 = Process(target=receiver, args=(queue,))
# 启动进程
process1.start()
process2.start()
# 等待进程完成
process1.join()
process2.join()
示例3:信号量同步
#include
#include
#include
sem_t sem;
void* thread1(void* arg) {
sem_wait(&sem);
printf("Thread 1 executed\n");
sem_post(&sem);
return NULL;
}
void* thread2(void* arg) {
sem_wait(&sem);
printf("Thread 2 executed\n");
sem_post(&sem);
return NULL;
}
int main() {
sem_init(&sem, 0, 1);
pthread_t t1, t2;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
sem_destroy(&sem);
return 0;
}