20211205ZX

导航

第四章:并发编程

第四章:并发编程

4.1:并行计算的简介
在早期,大多数计算机只有一个处理器(CPU),称为中央处理器。受硬件限制的影响,计算机程序通常是为串行计算而设计的。为了解决问题,需要设计算法并在计算机上以串行指令流的形式实现它。然而,很多算法具有高度的并行性,即可以同时执行多个任务。为了利用并行计算加快速度,需要使用多个处理器来实现并行计算。随着多核处理器的出现,使得普通程序员也能够进行并行计算。可以说,并行计算是计算的未来发展方向。

4.1.1:顺序算法与并行算法
顺序算法可以包含多个步骤,每个步骤都是通过单个任务按顺序执行的。当所有步骤执行完毕时,算法结束。而并行算法使用cobegin-coend代码块来指定并行算法中的独立任务。这些任务将并行执行,而cobegin-coend代码块之后的下一个步骤将在所有任务完成后执行。

4.1.2:并行性与并发性
并行算法通常只识别可以并行执行的任务,但并不规定如何将任务映射到处理器上。在理想情况下,所有任务应该同时实时执行,但这需要多个处理器,如多处理器或多核系统。在单个CPU系统中,只能并发执行任务,即逻辑上的并行执行。在单CPU系统中,通过多任务处理来实现并发性。

4.2:线程
4.2.1:线程的原理
操作系统包含多个并发进程,每个进程是一个独立的执行单元,可以在内核模式或用户模式下执行。线程是进程中的独立执行单元,多个线程可以在同一地址空间中执行。一个进程创建后会有一个主线程,可以创建其他线程。每个线程也可以创建更多的线程。线程拥有独立的执行堆栈。在线程模型中,一个线程被挂起时,其他线程可以继续执行。除了共享地址空间,线程还共享进程的其他资源,如用户id、打开的文件描述符和信号。可以将进程比作有房屋管理员(主线程)的房屋,线程则是住在房屋中的人。每个人可以独立地做自己的事情,但他们会共享一些公共设施,如信箱、厨房和浴室。现在,大多数操作系统都支持线程。

4.2.2:线程的优点
使用线程创建和切换速度更快。创建线程时,操作系统不需要分配额外的内存或创建页表,因为线程共享进程的地址空间。因此,创建线程比创建进程更快。
线程的响应速度更快。在一个进程中,当一个线程被挂起时,其他线程可以继续执行。而在进程中,当一个进程被挂起时,整个进程都会停止执行。
线程更适合并行计算。并行计算的目标是使用多个执行路径更快地解决问题。基于分治原则的算法经常表现出高度的并行性,通过使用并行或并发执行可以提高计算速度。

4.2.3:线程的缺点
由于线程共享地址空间,需要进行明确的同步来避免竞争条件。这意味着在多线程环境下,需要更加小心地管理共享的数据和资源,否则会出现问题。
许多库函数不是线程安全的,需要进行额外的工作来适应多线程环境。
在单个CPU系统上,使用线程解决问题实际上会比使用顺序程序慢,因为线程创建和切换的开销较大。

4.3:线程操作
线程可以在内核模式或用户模式下执行。在用户模式下,线程共享进程的地址空间,但每个线程拥有独立的执行堆栈。线程是独立的执行单元,可以通过系统调用进行挂起、激活等操作。

4.4:线程管理函数
4.4.1:创建线程
通过pthread_create()函数创建线程:
int pthread_create(pthread_t *pthread_id, pthread_attr_t *attr, void *(*func)(void *), void *arg);
成功时返回0,失败时返回错误代码。函数参数解释如下:

  • pthread_id:指向pthread_t类型变量的指针,用于存储线程的ID。
  • attr:指向线程属性的指针,可以为NULL表示使用默认属性。
  • func:要执行的新线程的入口地址。
  • arg:指向线程函数参数的指针。

4.4.2:线程ID
线程ID是一个不透明的数据类型,取决于具体实现。因此,不应直接比较线程ID,可以使用pthread_equal()函数进行比较:
int pthread_equal(pthread_t tl, pthread_t t2);

4.4.3:线程终止
当线程函数结束时,线程即终止。也可以使用pthread_exit()函数显式终止线程,其中状态是线程的退出状态。通常,0表示正常终止,非0表示异常终止。

4.4.4:线程连接
一个线程可以等待另一个线程的终止,使用pthread_join()函数进行连接,并通过status_ptr返回线程的退出状态。

4.5:线程示例程序
下面是一个计算N×N整数矩阵中所有元素之和的示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define N 4

int A[N][N], sum[N];

void *func(void *arg) {
int j, row;
pthread_t tid = pthread_self();
row = (int)arg;
printf(“Thread %d [%lu] computes sum of row %d\n”, row, tid, row);
for (j = 0; j < N; j++) {
sum[row] += A[row][j];
}
printf(“Thread %d [%lu] done: sum[%d] = %d\n”, row, tid, row, sum[row]);
pthread_exit((void *)0);
}

int main(int argc, char *argv[]) {
pthread_t thread[N];
int i, j, r, total = 0;
void *status;

printf("Main: initialize A matrix\n");
for (i = 0; i < N; i++) {
    sum[i] = 0;
    for (j = 0; j < N; j++) {
        A[i][j] = i * N + j + 1;
        printf("%4d", A[i][j]);
    }
    printf("\n");
}

printf("Main: create %d threads\n", N);
for (i = 0; i < N; i++) {
    pthread_create(&thread[i], NULL, func, (void *)i);
}

printf("Main: try to join with threads\n");
for (i = 0; i < N; i++) {
    pthread_join(thread[i], &status);
    printf("Main: joined with %d [%lu]: status = %d\n", i, thread[i], (int)status);
}

printf("Main: compute and print total sum: ");
for (i = 0; i < N; i++) {
    total += sum[i];
}
printf("total = %d\n", total);

pthread_exit(NULL);

}

4.6:线程同步
在并发程序中,多个线程共享资源时,需要确保共享数据的完整性和线程的协调性。为了防止竞争条件和支持线程协作,需要线程同步机制。互斥量(锁)、条件变量、信号量和屏障都是常用的线程同步机制。

4.6.1:互斥量
互斥量是一种线程同步的机制,它可以用来保护共享资源,只允许一个线程访问该资源。在Pthreads中,可以通过静态方式或动态方式创建互斥量。

4.6.2:死锁预防
死锁是一种状态,在该状态下,多个执行实体相互等待,无法继续下去。为了防止死锁的发生,可以使用死锁预防方法,在设计并行算法时避免可能的死锁情况。

4.6.3:条件变量
条件变量是一种线程同步的机制,用于线程之间的协作。在Pthreads中,使用pthread_cond_t类型声明条件变量,需要初始化后才能使用。

4.6.4:生产者-消费者问题
生产者-消费者问题是一种典型的线程同步问题,一组生产者进程和一组消费者进程共享一个缓冲区。只有当缓冲区为空时,消费者才能从中取出数据;只有当缓冲区为满时,生产者才能将数据放入缓冲区。

4.6.5:信号量
信号量是一种线程同步的机制,包含一个计数器和相关的操作。在Pthreads中,可以使用初始值为1的信号量作为锁,用于保护临界区。信号量的初始值可以用于控制线程协作。相比条件变量,信号量更通用且更灵活。

4.6.6:屏障
屏障提供了一种线程同步的方法,可以在特定点将线程阻塞,直到所有线程都到达该点。创建屏障对象,然后在需要同步的线程中进行初始化。之后,主线程创建工作线程来执行任务,并使用pthread_barrier_wait()函数在屏障中同步线程的操作。

2.苏格拉底挑战
苏格拉底挑战是对传统教育方法的质疑和反思。传统教育注重灌输知识,学生被要求记忆和重复信息,但却缺乏对于问题的独立思考和批判性思维能力的培养。苏格拉底提出了一种新的教育方法,鼓励学生通过问问题来探索和发现知识。他认为学生应该思考问题并通过对话和讨论来互相学习和提高。

苏格拉底挑战强调学生主动参与学习过程,培养他们的批判性思维能力和解决问题的能力。这种教育方法强调学生的主体性和自主学习,鼓励他们质疑和挑战现有的观念和知识,以推动思维的发展和知识的创新。通过对话和讨论,学生可以学会自我表达和辩论,提高自己的思维和表达能力。

苏格拉底挑战对传统教育模式提出了一种革新的思路,促进了教育领域的改革和发展。通过引导学生主动思考和互动,教育可以成为一种更有意义和有效的过程,培养学生的思维能力和创造力,使他们成为有能力解决问题、适应变化和创新的人才。

 

posted on 2023-11-05 22:26  20211205ZX  阅读(24)  评论(0编辑  收藏  举报