Fork me on GitHub

线程(第四章)

并行计算导论

顺序算法与并行算法

  1. 顺序算法:begin-end代码块,所有步骤都是通过单个任务依次执行的,每次执行一个步骤。当所有步骤执行完成时,算法完成。
  2. 并行算法:cobegin-coend代码块,所有任务都是并行执行的。下一个步骤将只在所有这些任务完成之后执行。

并行性与并发性

  1. 并行性:只能在有多个处理组件的系统中实现。
  2. 并发性:不同的任务只能并发执行,即在逻辑上并行执行。

线程

优点

  1. 线程创建和切换速度更快
  2. 线程的响应速度更快
  3. 线程更适合并行计算

缺点

  1. 需要来自用户的明确同步
  2. 许多库函数可能对线程不安全
  3. 在单CPU系统上,使用线程解决问题实际上要比使用顺序程序慢

线程操作

线程可在内核模式或用户模式下执行

线程管理函数

创建线程

pthread_create()函数:成功返回0,如果失败则返回错误代码

线程ID

pthread_equal()函数:比较线程ID,不同返回0

线程终止

线程函数结束后终止,或使用函数pthread_exit进行显示终止

0表示正常终止

线程连接

pthread_join:终止线程的退出状态一status_ptr返回

线程同步

当多个线程试图修改同一共享变量或数据结构时,如果修改结果取决于线程的执行顺序,则称之为竞态条件

互斥量

初始化

  1. 静态方法,如

    pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

    定义互斥量m

  2. 动态方法:pthread_mutex_init()函数

死锁预防

互斥量使用封锁协议

条件变量

作为锁,互斥量仅用于确保县城只能互斥地访问临界区中的共享数据对象

条件变量提供了一种线程协作的方法,初始化:

  1. 静态方法,如:

    pthread_cond_t con = PTHREAD_COND_INITIALIZER;

    定义一个条件变量con

  2. 动态方法:pthread_cond_init()函数

生产者—消费者问题

信号量

信号量是进程同步的一般机制。信号量是一种数据结构

屏障

在某些情况下,保持线程活动会更好,但应要求他们在所有线程都达到指定同步点之前不能继续活动。

Pthreads中,可以采用的机制是屏障以及一系列屏障函数。首先,主线程创建一个屏障对象:

pthread_barrier_t barrier;

并且调用

pthread_barrier_init(&barrier NULL, nthreads);初始化

工作线程使用

pthread_barrier_wait(&barrier)在屏障中等待指定数量的线程到达屏障

linux中的线程

linux不区分进程和线程

线程只是一个与其他进程共享某些资源的进程

进程和线程都是由clone()系统调用创建的,具有以下原型:

int clone(int (*fn)(coid *), void *child_stack, int flags, void *arg)

clone()更像是一个线程创建函数,flag字段详细说明父进程和子进程共享的资源,包括:

  • CLONE_VM:父进程和子进程共享地址空间
  • CLONE_FS:父进程和子进程共享文件系统信息
  • CLONE_FILES:父进程和子进程共享打开的文件
  • CLONE_SIGHAND:父进程和子进程共享信号处理函数和已屏蔽信号

问题和解决思路

pthread_cancel()不能杀死线程

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <pthread.h>
  5 #include <string.h>
  6 
  7 void *func(void *arg){
  8     while(1);
  9     return NULL;
 10 }
 11 int main(){
 12     printf("main:pid=%d,tid=%lu\n",getpid(),pthread_self());
 13 
 14     pthread_t tid;
 15     int ret = pthread_create(&tid,NULL,func,NULL);
 16     if(ret != 0){
 17         fprintf(stderr,"pthread_create error:%s\n",strerror(ret));
 18         return 1;
 19     }
 20 
 21     ret = pthread_cancel(tid);
 22     if(ret != 0){
 23         fprintf(stderr,"pthread_cancel error:%s\n",strerror(ret));
 24         return 2;
 25     }
 26 
 27     pthread_exit((void*)0);
 28 
 29     return 0;
 30 }

img

原因:

使用pthread_cancel()终止线程,需要线程中存在取消点。

大致是需要线程中有陷入内核的操作,才会存在取消点

如果想要用pthread_cancel()终止一个没有陷入内核操作的线程,就需要手动添加取消点

在while循环中加入,pthread_testcancel()即可用pthread_cancel()杀死该线程

  7 void *func(void *arg){
  8     while(1) pthread_testcancel();
  9     return NULL;
 10 }

img

posted @ 2022-10-16 16:10  郭幸坤  阅读(38)  评论(0编辑  收藏  举报
1