• 线程(第四章)


    并行计算导论

    顺序算法与并行算法

    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

  • 相关阅读:
    python基础:多进程讲解
    vue 导出数据
    vue 导入excel数据组件
    vue 分页组件
    vue 点击空白区域隐藏div
    vue 类似淘宝选择地址组件
    js基础练习经典题(数组,质数,数组的遍历等等)
    js去重复
    理解CSS3里的Flex布局用法
    书写HTML5/CSS3的命名规则
  • 原文地址:https://www.cnblogs.com/kenneth2012/p/16796409.html
Copyright © 2020-2023  润新知