精华内容
下载资源
问答
  • 2017-07-05 12:31:43

    归并排序是典型的分治算法,所以可以用多线程来解决,在Linux平台上进行多线程编程,必须在编译时链接Linuxthread库,如下图所示:


    因为比较简单,就直接上代码了,讲各种排序的博客也比较多。

    #include <stdio.h>
    #include <pthread.h>
    #include <stdlib.h>
    #include <string.h>
    
    int *array_master;
    
    /* 归并函数 */
    void merge(int arr[], int left, int middle, int right)
    {
        int i, j, k;
        int half1 = middle - left + 1; /* 数组前一半的数据量 */
        int half2 = right - middle;  /* 数组后一半的数据量 */
    
        int first[half1], second[half2]; /* 声明两个临时数组,
                                         保存前半部分数据和后半部分数据 */
    
        /* 从 arr 数组复制 left 到 right 之间前半部分的数据 */
        for (i = 0; i < half1; i++) 
            first[i] = arr[left + i]; 
    
        /* 从 arr 数组复制 left 到 right 之间后半部分的数据 */
        for (j = 0; j < half2; j++) 
            second[j] = arr[middle + 1 + j];
    
        i = 0;
        j = 0;
        k = left;
    
        /* 比较两个临时数组的数,找出当前最小的数,然后按序存入 arr */
        while (i < half1 && j < half2) 
        {
    
            if (first[i] <= second[j]) 
            {
                arr[k] = first[i];
                ++i; 
            }
            else 
            {
                arr[k] = second[j];
                j++;
            }
    
            k++; /* arr 数组的索引 */
        }
    
        /* 将临时数组中剩余的数存入 arr 数组 */
        while (i < half1) 
        {
            arr[k] = first[i];
            i++;
            k++;
        }
    
        while (j < half2)
        {
            arr[k] = second[j];
            j++;
            k++;
        }
    }
    
    /* 归并排序函数 */
    void merge_sort(void* arg) 
    {
        /* 变量声明 */
        int *arr = array_master; /* 指向全局变量 array_master 数组 */
        int *argu = (int*)arg;
        int l = argu[0]; /* 由线程传入的参数,获得要排序数据的最小索引值 */
        int r = argu[1]; /* 由线程传入的参数,获得要排序数据的最大索引值 */
    
        /* 若 l==r 则不必排序 */
        if (l < r) 
        {    
            /* 声明两个线程描述符 */
            pthread_t tid1;
            pthread_t tid2;
    
            /* 声明调用线程处理函数的参数 */
            int arg1[2];
            int arg2[2];
    
            int middle;
            middle = (l + (r - 1)) / 2;
            arg1[0] = l;
            arg1[1] = middle;
            arg2[0] = middle + 1;
            arg2[1] = r;
    
            /* 由于用二分法对数组分成两部分分别排序,
            所以存在并行的可能,这里采用多线程 */
            pthread_create(&tid1, NULL, merge_sort, arg1);
            pthread_create(&tid2, NULL, merge_sort, arg2);
    
            /* 这里必须等待两部分数组都已排序完毕,才能进行归并,
            所以这里调用 pthread_join 使得线程同步 */
            pthread_join(tid1, NULL);
            pthread_join(tid2, NULL);
    
            /* 此时归并两个已排序子序列 */
            merge(arr, l, middle, r);
            pthread_exit(0);
        }
    }
    
    /* 主函数 */
    int main()
    {
        int array[] = {1,23,4,56,7,89};
        int array_length = sizeof(array)/sizeof(array[0]);
        array_master = array;
    
        int arg[2];
        arg[0] = 0;
        arg[1] = array_length;
    
        /* 创建线程执行归并排序 */
        pthread_t tid;
        pthread_create(&tid, NULL, merge_sort, arg);
    
        /* 进程同步 */
        pthread_join(tid, NULL);
    
        /* 打印已排序数组 */
        int j;
        for (j = 0; j < array_length; j++) 
                printf("%d\n", array_master[j]);
    
        return 0;
    }



    更多相关内容
  • 为实现多线程快速排序,提出基于Fork/Join框架的多线程快速排序,同时对排序算法进行优化。该算法主要用于大量数据需要进行排序处理的应用。
  • 利用Pthread多线程工具 实现桶排序的并行化,并在linux下调试通过。
  • 父进程创建三个子线程,第一个子线程对数组的前半部分进行选择排序,第二个子进程对数组的后半部分进行选择排序,第三个子线程对两个已经排序好的数组部分进行归并排序,最后当所有子线程结束之后,父进程输出排序好...
  • 利用文件映射和多线程技术对大数据文件进行排序排序使用了qsort函数,合并每个线程的排序结果使用了分治算法
  • 多线程快速排序

    2013-09-05 16:27:48
    多线程快速排序,应付网络编程的小作业是个好东西!
  • 多线程冒泡法排序

    2019-12-05 22:20:01
    java课的课后作业,要求实现数组的多线程冒泡排序并实现可视化,自己写了一个奇偶排序多线程,但效率较低,现在回顾一下老师课上讲的程序。 生成的界面如上 首先实现Button1的功能,生成随机的指定大小的数组 ...

    java课的课后作业,要求实现数组的多线程冒泡排序并实现可视化,自己写了一个奇偶排序的多线程,但效率较低,现在回顾一下老师课上讲的程序。
    左边是生成的数组大小,右边可选择线程
    生成的界面如上
    首先实现Button1的功能,生成随机的指定大小的数组

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
            // TODO add your handling code here:
            long len=(Long)jFormattedTextField1.getValue();
            int arr[]=new int[(int)len];
            for(int i=0;i<len;i++)
            {
             arr[i]=(int)(Math.random()*10000);
            }
            SortPane.ar=arr;
            
            this.repaint();
        }                  
    

    接着实现选择线程的按钮

        private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
            // TODO add your handling code here:
    
            Object value=jSpinner1.getValue();
            int tn= Integer.parseInt(value.toString());
            SortPane.mode=new int[tn];
           BubbleOrder[]bo=new BubbleOrder[tn];
    
            for(int i=0;i<tn;i++)
            {
              bo[i]= new BubbleOrder((SortPane)jPanel1,i,tn,SortPane.ar);
             
            }
       
         try {
                Thread.sleep(500);}catch(Exception e){}
        for(int i=0;i<tn;i++)
            {
              bo[i].start();
             
            }  
        } 
    

    输入的值为tn,最后生成tn个线程
    在SortPane中实现用直线表示数字大小的方法为:

        public void paint(Graphics g) {
            if(ar==null)
             super.paint(g); //To change body of generated methods, choose Tools | Templates.
            else{
                g.setColor(Color.gray);
                
          
          
          float w=this.getSize().width;
          float h=this.getSize().height; 
          g.fillRect(0, 0, this.getSize().width, this.getSize().height);
          g.setColor(Color.red);
          float w1=w/ar.length;
          w1=w1<1?1:(int)(w1+0.5);
          for(int i=0;i<ar.length;i++){
              
          g.drawLine((int)(i*w1), (int)h,(int)(i*w1) ,(int) (h*(1-ar[i]/10000.0)));//drawLine中的4个参数表示两个点的坐标
          }
          
            }
        
        }
    

    最重要的是如何实现多线程的冒泡排序以及使各线程之间同步,假设项目中使用的4个线程的冒泡排序,那么第一个线程排序下标为0,4,8…的数,第二个线程排序下标为1,5,9…的数,由此类推,当四个线程均排到最后一个数时再对最后四个数字进行排序从而找到整个数组中最小的数,找到最小的数之后再对剩下的数组按照相同的方法排序,直到只剩下4个数时用任意一个线程去排序即可得到有序的数组,下面对代码的每一步进行分析。
    1.将主函数中的参数传到各线程中,对于各参数的意义放到后面分析。

     public BubbleOrder(SortPane sp, int id, int tn, int ar[]) {
            this.id = id;
            this.tn = tn;
            ot = (int) Math.pow(tn, 2) - 1;
            this.ar = ar;
            this.sp = sp;
            BubbleOrder.len = ar.length;
    
        }
    

    2.对其进行数组每次排序后对最后四个数排序和对剩下的最后四个数排序的函数sort1进行分析

        void sort1(int len) {
            if (len > tn) {//判断是每次排序的最后找最小值还是对剩下的最后四个数
                for (int k = len - tn; k < len - 1; k++) {//一层for循环找最小值
                    if (ar[k] < ar[k + 1]) {
                        int ls = ar[k];
                        ar[k] = ar[k + 1];
                        ar[k + 1] = ls;
                    }
    
                }
            } else {//两层for循环进行排序
                for (int k = len; k > 0; k--) {
                    for (int j = 0; j < k - 1; j++) {
                        if (ar[j] < ar[j + 1]) {
                            int ls = ar[j];
                            ar[j] = ar[j + 1];
                            ar[j + 1] = ls;
                        }
                    }
                }
                exit = true;
            }
        }
    

    3.再对其中的排序函数进行分析,很容易知道此处的tn为线程数

        void sort(int len) {
            if (id > len - tn) {
                exit = true;//当剩余需排序的长度小于线程数时退出,然后采用单线程排序即可
            }
            for (int k = id; k < len - tn; k = k + tn) {//id是各线程声明的整型数值,表示线程的名字和线程排序的起点
                if (ar[k] < ar[k + tn]) {//将较小的数换到后面
                    int ls = ar[k];
                    ar[k] = ar[k + tn];
                    ar[k + tn] = ls;
                }
            }
        }
    

    3.分析线程里面的run函数
    一个for循环中,首先进行冒泡排序,然后用一个waiting表示当前线程已完成排序,等待其他线程,已完成排序的线程SortPane.get(id)方法得到false,在sortPane中声明的mode数组存储各线程的完成情况,若完成则赋值为1,

            public void run() {
            while (!exit) {
                System.out.print("Thread " + id + "   sorting\r\n");
                sort(len);
                //synchronized(SortPane.ar){
                waiting = true;
                try{
                 System.out.print("Thread " + id + "   waiting\r\n");
                 SortPane.add(id);
                 if(issorted(SortPane.mode))
                 {
                        sort1(len);
                        sp.repaint();
                        BubbleOrder.len--;
                        if (BubbleOrder.len==tn) {//当仅剩下和线程相等的数组时直接用sort1函数排序
                            sort1(len);
                            sp.repaint();
                            break;
                        }
                        SortPane.clear();
                        synchronized (SortPane.ii) {
                            SortPane.ii.notifyAll();
                        }
                 }
                 else
                 {
                     synchronized (SortPane.ii) {                       
                            //  SortPane.ar.notify();
                            if (exit) {
                                break;
                            }
                            SortPane.ii.wait();
                        }
                 }
                    
                } 
                catch (InterruptedException ex) {//好像没啥用
                }
                
    

    此处为SortPane的mode数组,用于表示各线程是否已完成当前线程的排序

      static   int[] mode;
      static   synchronized void add(int id)
        {
            mode[id]=1;
        }
    

    issorted为判断mode数组是否所有数字为1的函数

     boolean issorted(int a[])
        {
            boolean sorted=true;
            for(int i=0;i<a.length;i++)
            {
                if(a[i]!=1) sorted=false;
            }
            return sorted;
        }
    

    最后的效果如下
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • java对大数据量文件内容的多线程读取和排序.pdf
  • C#多线程排序例子

    热门讨论 2012-12-11 16:47:45
    一个小小的例子,用简单排序小例子诠释多线程的用法和多线程的效率等
  • 多线程排序-真香

    千次阅读 2019-12-25 21:00:17
    ​来源:公众号【编程珠玑】 作者:守望先生 ID:shouwangxiansheng 在《系统编程-多线程》中已经了解了多线程的一些特点,其中包括快!... 所有线程排序完成后,将每组排序好的数组合并 ...

    ​来源:公众号【编程珠玑】

    作者:守望先生

    ID:shouwangxiansheng

    在《系统编程-多线程》中已经了解了多线程的一些特点,其中包括快!那么今天就来看看如何利用多线程来排序。

    思路

    我们的思路是这样的:

    • 假设有N个线程,则将数组数M据分为N组

    • 每个线程对其中的一组数据使用库函数提供的快速排序算法

    • 所有线程排序完成后,将每组排序好的数组合并

    举个例子,使用4个线程对11个数据进行排序:

    12,10,4,7,9,6,8,1,5,16,11
    

    由于4不能被10整除,因此,前面三个线程,每个负责排序10%(4-1)= 3三个数,最后一个线程负责排序最后两个数。

    假设这4个线程都完成了自己的工作后,内容如下:


    比较每组的第一个,选出最小的一个,这里是线程2的1,放到新数组的下标0处最后由主线程将已经排好的每组进行合并:

    • 将1放到新的数组最开始的位置,线程的下次计较的内容后移,即下次比较时,比较线程2的第二个数。

    • 循环比较

    最终可以得到合并的数据:

    1 4 5 6 7 8 9 10 11 12 16
    

    屏障

    通过上面的分析,我们需要多个线程进行排序后,一起交给主线程合并,因此需要有方法等待所有线程完成事情之后,再退出。
    在《系统编程-多线程》中介绍了pthread_join,今天我们使用pthread_barrier_wait。

    #include <pthread.h>
    int pthread_barrier_destroy(pthread_barrier_t *barrier);
    int pthread_barrier_init(pthread_barrier_t *restrict barrier,
    const pthread_barrierattr_t *restrict attr, unsigned count);
    int pthread_barrier_wait(pthread_barrier_t *barrier);
    

    在解释之前说明一下基本原理,pthread_barrier_wait等待某一个条件达到(计数到达),一旦达到后就会继续往后执行。当然了,如果你希望各个线程完成它自己的工作,主线程再进行合并动作,则你等待的数量可以再加一个。:

    //来源:公众号【编程珠玑】
    //barrier.c
    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    pthread_barrier_t b;
    void *workThread(void * arg)
    {
        printf("thread %d\n",*(int*)arg);
        pthread_barrier_wait(&b);
        return (void*)0;
    }
    int main(void)
    {
        int threadNum = 4;
        int err;
        /*计数为创建线程数+1*/
        pthread_barrier_init(&b,NULL,threadNum + 1);
        int i = 0;
        pthread_t tid;
        /*创建多个线程*/
        for(i = 0;i < threadNum; i++)
        {
            err = pthread_create(&tid,NULL,workThread,(void*)&i);
            if(0 != err)
            {
                printf("create thread failed\n");
                return -1;
            }
            printf("tid:%ld\n",tid);
            usleep(10000);
        }
        pthread_barrier_wait(&b);
        printf("all thread finished\n");
        /*销毁*/
        pthread_barrier_destroy(&b);
        return 0;
    }
    

    其中,pthread_barrier_init用来初始化相关资源,而pthread_barrier_destroy用来销毁相关资源。
    编译运行:

    $ gcc -o barrier barrier.c  -lpthread
    $ ./barrier
    tid:140323085256448
    thread 0
    tid:140323076863744
    thread 1
    tid:140323068471040
    thread 2
    tid:140323060078336
    thread 3
    all thread finished
    

    比较函数

    为了使用qsort函数,我们需要实现自己的比较函数,参考《高级指针话题-函数指针》和《快速排序你真的会了吗?》:

    //来源:公众号【编程珠玑】
    //https:www.yanbinghu.com
    /*比较函数*/
    int compare(const void* num1, const void* num2)
    {
        long l1 = *(long*)num1;
        long l2 = *(long*)num2;
        if(l1 == l2)
            return 0;
        else if(l1 < l2)
            return -1;
        else
            return 1;
    }
    

    合并

    对于每个线程完成它自己的任务之后,需要合并所有内容,关于合并的逻辑前面已经举例了,这里不再多介绍。

    //来源:公众号【编程珠玑】
    //https://www.yanbinghu.com
    /*要排序的数组信息*/
    typedef struct SortInfo_t
    {
        long startIdx; //数组启始下标
        long num;//要排序的数量
    }SortInfo;
    /*合并线程已经排序好的内容*/
    void merge(SortInfo *sortInfos,size_t threadNum)
    {
        long idx[threadNum];
        memset(idx,0,threadNum);
        long i,minidx,sidx,num;
        for(i = 0;i < threadNum;i++)
        {
            idx[i] = sortInfos[i].startIdx;
        }
        for(sidx = 0;sidx < NUM;sidx++)
        {
            num = LONG_MAX;
            for(i = 0;i < threadNum;i++)
            {
                if(idx[i] < (sortInfos[i].startIdx + sortInfos[i].num) && (nums[idx[i]] < num))
                {
                    num = nums[idx[i]];
                    minidx = i;
                }
            }
            snums[sidx] = nums[idx[minidx]];
            idx[minidx]++;
        }
    }
    

    随机数生成

    关于生成方法,参考《随机数生成的N种姿势》。

    完整代码

    由于完整代码比较长,这里就不贴出了,有兴趣的可以访问:
    https://www.yanbinghu.com/2019/12/23/52416.html
     

    运行结果

    对800W数据进行排序,排序时间:

    $ threadSort 1
    thread num:1
    time 2.369488
    

    使用4个线程时:

    $ threadSort 4
    thread num:4
    time 1.029097
    

    可以看到速度提升是比较明显的。

    总结

    可以看到使用4线程排序要比单个线程排序快很多,不过以上实现仅供参考,本文例子可能也存在不妥之处,请根据实际数据情况选择合适的排序算法。但是,多线程就一定快吗?敬请关注下一篇。

    参考:《unix环境高级编程》

     

     

    我有一个问题,用了多线程后,两个问题有了现在

    面试必问:进程和线程有什么区别?

    快速排序你真的会了吗?

     

    关注公众号【编程珠玑】,获取更多Linux/C/C++/数据结构与算法/计算机基础/工具等原创技术文章。后台免费获取经典电子书和视频资源

     

    展开全文
  • 使用多线程 实现冒泡排序,选择排序,快速排序
  • 这是在WINDOWS下实现的多进程多线程的快速排序程序,其中为了加快排序速度使用了文件映射技术。
  • 上次传错了,这次绝对不会错了.比较适合新手哦.多线程的东西其实不要想得太复杂,自己亲手做了就会明白的
  • 多线程三大特性——重排序

    千次阅读 2021-12-01 20:12:24
    Java语言规范JVM线程内部维持顺序化语义,即只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码逻辑顺序不一致,这个过程就叫做指令的重排序。 指令重排序的意义:在Java中,JVM能够根据...
    public class ReorderingTest {
        private static boolean ready;
        private static int number;
    
        private static class ReaderThread extends Thread {
            @Override
            public void run() {
                while (!ready) {
                    Thread.yield();
                }
                System.out.println(number);
            }
        }
        public static void main(String[] args) {
            new ReaderThread().start();
            number = 42;
            ready = true;
        }
    }

    Java并发编程实战》的一个例子:ReaderThread线程可能会输出0。执行线程可能看到了写入ready的值,但却没有看到之后写入number的值。这种现象称为“重排序(Reordering)”。

    指令重排序

    Java语言规范JVM线程内部维持顺序化语义,即只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码逻辑顺序不一致,这个过程就叫做指令的重排序。

    指令重排序的意义:在Java中,JVM能够根据处理器特性(CPU多级缓存系统、多核处理器等)适当对机器指令进行重排序,最大限度发挥机器性能

    Java中的指令重排序有两次,第一次发生在将字节码编译成机器码的阶段,第二次发生在CPU执行的时候,也会适当对指令进行重排。

    为了尽可能减少内存操作速度远慢于CPU运行速度所带来的CPU空置的影响,虚拟机会按照自己的一些规则将程序编写顺序打乱——即写在后面的代码在时间顺序上可能会先执行,而写在前面的代码会后执行——以尽可能充分地利用CPU。

    private static byte[] a = new byte[1024*1024];

    private static boolean flag=false;

    JVM先执行 a=new byte[1024*1024](分配1M空间),那么它会运行地很慢,此时CPU是等待其执行结束呢,还是先执行下面那句flag=true呢?显然,先执行flag=true可以提前使用CPU,加快整体效率,当然这样的前提是不会产生错误。

    这里有两种情况:后面的代码先于前面的代码开始执行;前面的代码先开始执行,但当效率较慢的时候,后面的代码开始执行并先于前面的代码执行结束。不管谁先开始,总之后面的代码在一些情况下存在先结束的可能。

    指令重排序的类型

    在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序。重排序分三种类型:

    • 编译器优化的重排序

    编译器在不改变单线程程序语义的前提下(代码中不包含synchronized关键字),可以重新安排语句的执行顺序。

    • 指令级并行的重排序

    现代处理器采用了指令级并行技术(Instruction-Level Parallelism, ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。

    • 内存系统的重排序

    由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。


    从java源代码到最终实际执行的指令序列,会分别经历下面三种重排序:

    这里写图片描述

    上述第一个类型属于编译器重排序,第2和第3属于处理器重排序。这些重排序都可能会导致多线程程序出现内存可见性问题。对于编译器,JMM的编译器重排序规则会禁止特定类型的编译器重排序(不是所有的编译器重排序都要禁止)。对于处理器重排序,JMM的处理器重排序规则会要求java编译器在生成指令序列时,插入特定类型的内存屏障(memory barriers,intel称之为memory fence)指令,通过内存屏障指令来禁止特定类型的处理器重排序(不是所有的处理器重排序都要禁止)。

    JMM属于语言级的内存模型,它确保在不同的编译器和不同的处理器平台之上,通过禁止特定类型的编译器重排序和处理器重排序,为程序员提供一致的内存可见性保证。

    处理器重排序

    现代的处理器使用写缓冲区来临时保存向内存写入的数据。写缓冲区可以保证指令流水线持续运行,它可以避免由于处理器停顿下来等待向内存写入数据而产生的延迟。同时,通过以批处理的方式刷新写缓冲区,以及合并写缓冲区中对同一内存地址的多次写,可以减少对内存总线的占用。虽然写缓冲区有这么多好处,但每个处理器上的写缓冲区,仅仅对它所在的处理器可见。这个特性会对内存操作的执行顺序产生重要的影响:处理器对内存的读/写操作的执行顺序,不一定与内存实际发生的读/写操作顺序一致。

    这里写图片描述

    这里处理器A和处理器B可以同时把共享变量写入自己的写缓冲区(A1,B1),然后从内存中读取另一个共享变量(A2,B2),最后才把自己写缓存区中保存的脏数据刷新到内存中(A3,B3)。当以这种时序执行时,程序就可以得到a=b=0的结果。

    从内存操作实际发生的顺序来看,直到处理器A执行A3来刷新自己的写缓存区,写操作A1才算真正执行了。虽然处理器A执行内存操作的顺序为:A1->A2,但内存操作实际发生的顺序却是:A2->A1。此时,处理器A的内存操作顺序被重排序了。

    这里的关键是,由于写缓冲区仅对自己的处理器可见,它会导致处理器执行内存操作的顺序可能会与内存实际的操作执行顺序不一致。由于现代的处理器都会使用写缓冲区,因此现代的处理器都会允许对写-读操作重排序。

    处理器/重排序类型Load-LoadLoad-StoreStore-StoreStore-Load数据依赖
    sparc-TSONNNYN
    x86NNNYN
    ia64YYYYN
    PowerPCYYYYN

    注:上表单元格中的“N”表示处理器不允许两个操作重排序,“Y”表示允许重排序。

    从上表我们可以看出:常见的处理器都允许Store-Load重排序;常见的处理器都不允许对存在数据依赖的操作做重排序。sparc-TSO和x86拥有相对较强的处理器内存模型,它们仅允许对写-读操作做重排序(因为它们都使用了写缓冲区)。
     

    禁止指令重排序

    对象溢出

    public class Singleton {
        private /**volatile**/ static Singleton instance;
        private Singleton() {}
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

    创建类实例的步骤:

    1、memory = allocate() 分配对象内存空间

    2、ctorInstance() 初始化对象

    3、instance = memory 指针重定向

    由于JVM和CPU优化,多线程环境下可能会发生指令重排序,顺序变为1、3、2。此时对象还没有完成初始化,可能就会出现一个线程检测到instance不为空,而直接获取instance去使用对象导致错误。

    发布对象:使一个对象能被当前范围之外的代码所使用。

    对象溢出:一种错误的发布。当一个对象还没有构造完成时,就使它被其他线程所见。

    虚拟机规范

    as-if-serial

    数据依赖性

    如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性。数据依赖分下列三种类型,只要重排序两个操作的执行顺序,程序的执行结果将会被改变:

    名称代码示例说明
    写后读a = 1;b = a;写一个变量之后,再读这个位置。
    写后写a = 1;a = 2;写一个变量之后,再写这个变量。
    读后写a = b;b = 1;读一个变量之后,再写这个变量。

    注:这里所说的数据依赖性仅针对单个处理器中执行的指令序列和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑。

    编译器和处理器可能会对操作做重排序。编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。

    as-if-serial语义

    不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。编译器,runtime 和处理器都必须遵守as-if-serial语义。为了遵守as-if-serial语义,编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。

    操作之间不存在数据依赖关系,这些操作可能被编译器和处理器重排序。

    double pi  = 3.14;         //A
    double r   = 1.0;          //B
    double area = pi * r * r;  //C

    A和C之间存在数据依赖关系,同时B和C之间也存在数据依赖关系。因此在最终执行的指令序列中,C不能被重排序到A和B的前面(C排到A和B的前面,程序的结果将会被改变)。但A和B之间没有数据依赖关系,编译器和处理器可以重排序A和B之间的执行顺序。

    A------------>B----------------C  //按程序顺序执行结果 area = 3.14
    B------------>A----------------C  //重排序后的执行结果 area = 3.14

    as-if-serial语义把单线程程序保护了起来,遵守as-if-serial语义的编译器、runtime 和处理器共同为编写单线程程序的程序员创建了一个幻觉:单线程程序是按程序的顺序来执行的。as-if-serial语义使单线程程序员无需担心重排序会干扰他们,也无需担心内存可见性问题。
     

    Happens-Before

    两个操作之间具有happens-before关系,并不意味着前一个操作必须要在后一个操作之前执行!happens-before仅仅要求前一个操作(执行的结果)对后一个操作可见,且前一个操作按顺序排在第二个操作之前(the first is visible to and ordered before the second)

    内存屏障

    内存屏障正是通过阻止屏障两边的指令重排序来避免编译器和硬件的不正确优化而提出的一种解决办法。

    CPU

    指令原语:(intel) lfence sfence mfence(mixed fence) 原语前后的指令不能重排序

    总线锁:原子指令如x86上的lock...指令是一个full barrier,执行时会锁住内存子系统保证执行顺序,甚至跨多个cpu。

    lock用于在多处理器中执行指令时对共享内存的独占使用。它的副作用是能够将当前处理器对应缓存的内容刷新到内存,并使其他处理器对应的缓存失效。另外还提供了有序的指令无法越过这个内存屏障的作用。

    文献

    JVM(十一)Java指令重排序_keep_trying的专栏-CSDN博客_java指令重排序

    多线程基础——内存屏障_城南孔乙己的专栏-CSDN博客

    展开全文
  • C语言实现多线程的归并排序

    千次阅读 2019-04-03 10:01:11
    C语言实现多线程的归并排序 问题 ​ 利用多线程实现归并排序。归并排序是分治算法的代表,适合改写为多线程。 构造数据 ​ 数据规模为2∗1062*10^62∗106,整数。array_length=2∗106array\_length = 2*10^6array_...
  • 多线程排序win32

    2011-09-03 23:09:14
    多线程 排序 win32 多线程 排序 win32 多线程 排序 win32 多线程 排序 win32 多线程 排序 win32 多线程 排序 win32 多线程 排序 win32 多线程 排序 win32 多线程 排序 win32 多线程 排序 win32 多线程 排序 win32 ...
  • 如何用多线程实现归并排序

    千次阅读 多人点赞 2018-08-09 22:45:17
    之前听吴恩达老大说过Python里面的Numpy包的矩阵运算就是多线程的,所以能做到的情况下尽量用矩阵运算代替循环,这样能大大加快运算的速度。 为了提高速度,如果不涉及外部资源读取的话,要提高运行速度就要做到...
  • 多线程排序+快速排序

    万次阅读 2017-05-24 20:07:48
    多线程排序,主要是将整个排序的序列分成若干份,每一个线程排序一份,所以线程排序完成之后,就进行归并,相当于多个有序序列合并成一个有序序列。 这里就需要用到线程屏障,也就是 pthread_barrier 系列函数...
  • 这是一个简单的运用多线程的程序 主要对快速排序等多个算法进行比较
  • 多线程实现睡眠排序排序的数非负) 样例输入: 1 5 6 2 3 6 9 样例输出 1 2 3 5 6 6 9 睡眠排序算法见百度。 有能力的可以实现支持负数的排序
  • 一、要求及主要函数 ... 文件名从0到9,当前有两个线程, 0号线程排序0 2 4 6 8号文件, 1号线程排序1 3 5 7 9号文件 pthread_create 功能  pthread_create是UNIX环境创建线程函数 函数原型  
  • 多线程之重排序详解

    千次阅读 2018-11-07 14:17:56
    排序排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。 数据依赖性 如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据的依赖性。数据...
  • 由于最近在学习C++从底层(指针,对象模型,内存管理)再到网络socket编程,多线程编程,数据库编程等方面知识,需要从Java慢慢的迁移过来。这是以前学习Java的学习路线,所以就把原来Java的做的项目全部用C++重新实现...
  • mybatis多线程查询数据库

    千次阅读 2019-04-21 17:10:09
    查询费用汇总和明细时使用1条sql查询在数据库阻塞锁表,所以拆成4条小sql,先按分页和查询条件查询出满足的customerCd再通过customerCd多线程4次异步调用查询数据和未结算金额及结算金额和总条数 在查询group by和...
  • 多线程实现快速排序

    千次阅读 2019-04-28 18:01:04
    多线程排序,主要是将整个排序的序列分成若干份,每一个线程排序一份,所以线程排序完成之后,就进行归并,相当于多个有序序列合并成一个有序序列。 这里就需要用到线程屏障,也就是pthread_barrier 系列函数。 ...
  • 这是一个使用了多线程的快速排序算法的源代码,如果CPU和内存足够,在32位平台下,最大可以对5亿个int数据进行排序(考虑系统本身所需的内存,程序本身运行所需的内存)。 不支持文件。 待排序的数据由程序自动生成...
  • C#-多线程排序示例

    2011-06-07 14:45:48
    C# 的多线程排序示例 C# 的多线程排序示例 C# 的多线程排序示例 C# 的多线程排序示例 适合初学者使用
  • 对大规模文件进行排序操作,首先将文件分割以便在内存中进行内排序.使用堆排序的方法对每个子文件排序.多线程实现.
  • 多进程与多线程使用合并排序:提交给Sumaiyah小姐的多线程与多处理OS项目使用合并排序
  • Linux 下多线程排序的实现

    千次阅读 2016-04-01 15:57:56
    这篇博文实现了多线程排序,同时讲解了一些需要注意的问题。 首先,说一下总体的思路:将元素分成n段,使用快速排序多个线程并行处理。最后需要等待这些线程都将分段排好序之后,进行类似归并排序的过程。 这样时间...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 338,914
精华内容 135,565
关键字:

多线程查询排序