精华内容
下载资源
问答
  • C++ 多线程通信方式简介并结合生产者-消费者模式代码实现
  • 本周的学习计划是Android通信模块,内容:单线程,多线程通信方式,Handler 与UI Thread的交互,Handler接合子线程的使用。 二丶效果演示(源码链接见文末) 三丶实现功能 1.演示使用Handler常见崩溃 2....

    本文出自:http://blog.csdn.net/dt235201314/article/details/73823653

    一丶概述

    本周的学习计划是Android通信模块,内容:单线程,多线程通信方式,Handler 与UI Thread的交互,Handler接合子线程的使用。

    二丶效果演示(源码链接见文末)


    三丶实现功能

    1.演示使用Handler常见崩溃

    2.handler更新TextView的UI

    3.实现图片轮播及停止

    4.输出handleMessage(Message mes)的mes打印

    5.自定义线程相关handler测试执行

    6.Handler异步消息处理测试

    handler相关方法运用

    四丶正文

    1.选说说多线程(工作到现在用的不太多,都是别人封装好的框架直接用)

    入门文章 菜鸟教程:Java多线程编程

    2.Handler

    最初学习Handler是通过扣丁学堂,之前的文章:扣丁学堂——Handler

    后面在开发扣丁音乐闪屏页面延时跳转功能时也有用到Handler。文章链接:扣丁音乐(一)——闪屏页SplashActivity(欢迎界面)

    最近开发用到的SwipeRefreshLayout 的onRefresh()方法,也常看到handler

    @Override
    public void onRefresh() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mEntities.clear();
                intData();
                //★3.通知recycleView改变了数据
                homeAdapter.notifyDataSetChanged();
                //★4.记得关闭刷新,否则刷新球一直在转
                mSwipeRefreshLayout.setRefreshing(false);
            }
        }, 50);
    }
    以上基本是在整理文章前关于handler的所有运用。

    好了,现在重新认识

    2.Handler类的引入:

    3.Handler的执行流程图:

    流程图解析: 
    相关名词

    • UI线程:就是我们的主线程,系统在创建UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue;
    • Handler:作用就是发送与处理信息,如果希望Handler正常工作,在当前线程中要有一个Looper对象
    • Message:Handler接收与处理的消息对象
    • MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue;
    • Looper:每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理!

    简单点说:

    当我们的子线程想修改Activity中的UI组件时,我们可以新建一个Handler对象,通过这个对象向主线程发送信息;而我们发送的信息会先到主线程的MessageQueue进行等待,由Looper按先入先出顺序取出,再根据message对象的what属性分发给对应的Handler进行处理!



    4.Handler的相关方法:

    • void handleMessage(Message msg):处理消息的方法,通常是用于被重写!
    • sendEmptyMessage(int what):发送空消息
    • sendEmptyMessageDelayed(int what,long delayMillis):指定延时多少毫秒后发送空信息
    • sendMessage(Message msg):立即发送信息
    • sendMessageDelayed(Message msg):指定延时多少毫秒后发送信息
    • final boolean hasMessage(int what):检查消息队列中是否包含what属性为指定值的消息 
      如果是参数为(int what,Object object):除了判断what属性,还需要判断Object属性是否为指定对象的消息

    5.看代码

    1.非UI线程线程更新UI崩溃测试:

    case R.id.id_btn1:
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000 * 3);
                    idTv.setText("蹦啦");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        break;
    case R.id.id_btn2:
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000 * 3);
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            idTv.setText("又长帅了");
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        break;

    关于这里有个小插曲,涉及源码解读,观看爱哥博客

    为什么我们可以在非UI线程中更新UI


    2.循环播放图片及停止

    Handler handler = new Handler();
    Thread myThread = new Thread(){
        @Override
        public void run() {
            index++;
            index = index%3;
            System.out.println(index);
            idImg.setImageResource(images[index]);
            handler.postDelayed(myThread,1000);
        }
    };
    点击事件

    case R.id.id_btn3:
        handler.postDelayed(myThread,1000);
        break;
    case R.id.id_btn4:
        handler.removeCallbacks(myThread);

    handler.postDelayed(X,X)是延迟执行线程

    handler.removeCallbacks(X)移除线程中所有消息和回调


    3.handle传递message可携带的内容有(int 实体内等)

    Handler customHander = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            idTv.setText("msg.arg1>"+msg.arg1+ "\nmsg.arg2>" +msg.arg2 +"\nmsg.obj>"+((Person)msg.obj).toString());
        }
    };
    点击事件

                case R.id.id_btn5:
                    Person dog=new Person("金三胖",1);
    //                Message message = new Message();
                    Message message= customHander.obtainMessage();
                    message.arg1 = 1;
                    message.arg2 = 2;
                    message.obj = dog;
    //                customHander.sendMessage(message);
                    message.sendToTarget();
                    break;

    4.消息拦截测试

    Handler interceptHander = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            Toast.makeText(HandlerDemoActivity.this, "callback handleMessage", Toast.LENGTH_SHORT).show();
            System.out.println("is intercept Handler>"+msg.what);
            // 设置true拦截消息
            return true;
        }
    }){
        @Override
        public void handleMessage(Message msg) {
            System.out.println("is intercept Handler");
        }
    };
    点击事件

    case R.id.id_btn6:
        interceptHander.sendEmptyMessage(1);
        break;
    5.子线程中实例化hangler崩溃测试

      case R.id.id_btn7:
                    new Thread() {
                        @Override
                        public void run() {
                            try {
                                Thread.sleep(1000*3);
    //                    idTv.setText("UI线程更新UI会出现什么异常呢?");
                                new Handler().post(new Runnable() {
                                    @Override
                                    public void run() {
                                        idTv.setText("又蹦啦");
                                    }
                                });
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }.start();
                    break;
    6.自定义一个与线程相关Handler

    public class HandlerActivity extends AppCompatActivity {
        private MyThread myThread;
        private Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                System.out.println("UI ==:"+ Thread.currentThread());
            }
        };
    
        class MyThread extends Thread {
            public Handler handler;
            @Override
            public void run() {
                Looper.prepare();
                handler= new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        System.out.println("currentThread:=="+ Thread.currentThread());
                    }
                };
                Looper.loop();
            }
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler);
            myThread = new MyThread();
            myThread.start();
            try {
                Thread.sleep(1000*5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myThread.handler.sendEmptyMessage(1);
            handler.sendEmptyMessage(1);
        }
    }
    
    效果打印:

    06-29 17:07:30.519 9652-11848/com.example.jinboy.codertodeveloperbytcler I/System.out: currentThread:==Thread[Thread-9681,5,main]
    06-29 17:07:30.659 9652-9652/com.example.jinboy.codertodeveloperbytcler I/System.out: UI ==:Thread[main,5,main]


    7.Handler异步消息处理

    public class HandlerThreadActivity extends AppCompatActivity implements View.OnClickListener {
        private Button idBtn1,idBtn2;
        private Handler threadhandler;
        private HandlerThread thread;
    
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                System.out.println("UI thread==>" + Thread.currentThread());
                // 给主线程发送消息
                Message message = new Message();
                message.what =1;
                threadhandler.sendMessageDelayed(message, 1000);
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler_thread);
            idBtn1 = (Button) findViewById(R.id.id_btn1);
            idBtn2 = (Button) findViewById(R.id.id_btn2);
            idBtn1.setOnClickListener(this);
            idBtn2.setOnClickListener(this);
            thread = new HandlerThread("Handler Thread");
            thread.start();
            threadhandler = new Handler(thread.getLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    // 处理耗时操作
                    System.out.println("current thread==>" + Thread.currentThread());
                    // 给主线程发送消息
                    Message message = new Message();
                    message.what =1;
                    handler.sendMessageDelayed(message, 1000);
                }
            };
    //        threadhandler.sendEmptyMessage(1);
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.id_btn1:
                    handler.sendEmptyMessage(1);
                    break;
                case R.id.id_btn2:
                    handler.removeMessages(1);
                    threadhandler.removeMessages(1);
                    break;
            }
        }
    }
    
    打印输出


    五丶参考链接和拓展学习

    参考内容:

    小猪博客:http://my.csdn.net/zpj779878443

    慕课网课程-Android面试常客Handler详解

    Android异步消息处理机制完全解析-Handler详解

    拓展学习:

    40个Java多线程问题总结

    android进行异步更新UI的四种方式

    Handler源码解析

    HandlerThread的使用以及原理

    Android HandlerThread 完全解析

    Android异步消息处理机制完全解析,带你从源码的角度彻底理解

    六丶日常开发案例

    1.Android避免在主线程进行网络请求和UI操作

    方法一:线程请求网络+Handler更新UI

    //handler 处理返回的请求结果
    handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Bundle data = msg.getData();
            String val = data.getString("value");
            tv_name.setText(tvName);
            tv_originalArticleNumber.setText(tvOriginalArticleNumber);
            tv_visitNumber.setText(tvVisitNumber);
            tv_mark.setText(tvMark);
            tv_rank.setText(tvRank);
            Log.i("mylog", "请求结果-->" + val);
        }
    };
    
    //新线程进行网络请求
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            BlogAuthor blogAuthor = JsoupUtil.getBlogAutoMessage();
            tvName = blogAuthor.getAuthorName() + "\n" + blogAuthor.getCode()
                    + "\n" + blogAuthor.getMyHelloWorld();
            tvOriginalArticleNumber = blogAuthor.getOriginalArticleNumber();
            tvVisitNumber = blogAuthor.getVisitNumber();
            tvMark = blogAuthor.getMark();
            tvRank = blogAuthor.getRank();
            Message msg = new Message();
            Bundle data = new Bundle();
            data.putString("value", "请求结果");
            msg.setData(data);
            handler.sendMessage(msg);
        }
    };
    new Thread(runnable).start();  //启动子线程
    方法二:强制在UI线程更新UI请求网络

    setContentView(R.layout.activity_main);
    if (android.os.Build.VERSION.SDK_INT > 9) {
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
    }

    源码下载欢迎Star(updating):https://github.com/JinBoy23520/CoderToDeveloperByTCLer




    展开全文
  • 下面小编就为大家带来一篇深入理解JAVA多线程之线程间的通信方式。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 多线程实现Socket通信 多线程实现Socket通信 多线程实现Socket通信
  • 操作系统的主要任务是管理计算机的软件、硬件资源。...因此多进程和多线程间为了完成一定的任务,就需要进行一定的通信。而线程间通信又和进程间的通信不同。由于进程的数据空间相对独立而线程是共享数据空间的,

    操作系统的主要任务是管理计算机的软件、硬件资源。现代操作系统的主要特点是多用户和多任务,也就是程序的并行执行,windows如此linux也是如此。所以操作系统就借助于进程来管理计算机的软、硬件资源,支持多任务的并行执行。要并行执行就需要多进程、多线程。因此多进程和多线程间为了完成一定的任务,就需要进行一定的通信。而线程间通信又和进程间的通信不同。由于进程的数据空间相对独立而线程是共享数据空间的,彼此通信机制也很不同。

             线程间通信:由于多线程共享地址空间和数据空间,所以多个线程间的通信是一个线程的数据可以直接提供给其他线程使用,而不必通过操作系统(也就是内核的调度)。

             进程间的通信则不同,它的数据空间的独立性决定了它的通信相对比较复杂,需要通过操作系统。以前进程间的通信只能是单机版的,现在操作系统都继承了基于套接字(socket)的进程间的通信机制。这样进程间的通信就不局限于单台计算机了,实现了网络通信。

            进程的通信机制主要有:管道、有名管道、消息队列、信号量、共享空间、信号、套接字。

            管道:它传递数据是单向性的,只能从一方流向另一方,也就是一种半双工的通信方式;只用于有亲缘关系的进程间的通信,亲缘关系也就是父子进程或兄弟进程;没有名字并且大小受限,传输的是无格式的流,所以两进程通信时必须约定好数据通信的格式。管道它就像一个特殊的文件,但这个文件之存在于内存中,在创建管道时,系统为管道分配了一个页面作为数据缓冲区,进程对这个数据缓冲区进行读写,以此来完成通信。其中一个进程只能读一个只能写,所以叫半双工通信,为什么一个只能读一个只能写呢?因为写进程是在缓冲区的末尾写入,读进程是在缓冲区的头部读取,他们各自
    的数据结构不同,所以功能不同。

            有名管道:看见这个名字就能知道个大概了,它于管道的不同的是它有名字了。这就不同与管道只能在具有亲缘关系的进程间通信了。它提供了一个路径名与之关联,有了自己的传输格式。有名管道和管道的不同之处还有一点是,有名管道是个设备文件,存储在文件系统中,没有亲缘关系的进程也可以访问,但是它要按照先进先出的原则读取数据。同样也是单双工的。

            消息队列:是存放在内核中的消息链表,每个消息队列由消息队列标识符标识,于管道不同的是,消息队列存放在内核中,只有在内核重启时才能删除一个消息队列,内核重启也就是系统重启,同样消息队列的大小也是受限制的。

            信号量:也可以说是一个计数器,常用来处理进程或线程同步的问题,特别是对临界资源的访问同步问题。临界资源:为某一时刻只能由一个进程或线程操作的资源,当信号量的值大于或等于0时,表示可以供并发进程访问的临界资源数,当小于0时,表示正在等待使用临界资源的进程数。更重要的是,信号量的值仅能由PV操作来改变。

            共享内存:就是分配一块能被其他进程访问的内存。共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。首先说下在使用共享内存区前,必须通过系统函数将其附加到进程的地址空间或说为映射到进程空间。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到 进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互
    斥锁和信号量都可以。采用共享内存通信的一个显而易 见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而 共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就 解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存 中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。

             信号:信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。信号事件的发生有两个来源:硬件来源(比如我们按下了键盘或者其它硬件故障);软件来源。信号分为可靠信号和不可靠信号,实时信号和非实时信号。进程有三种方式响应信号1.忽略信号2.捕捉信号3.执行缺省操作。

            套接字:这一块在网络编程那一块讲的 很多,在此就不在说拉。

    **********************************************************************************************************************

    windows下多线程通信方法

    多线程知识简介

    同一进程中可以包含多个线程,由于进程中的多个线程可以共享进程中的资源,所以使同一进程中的多个线程之间通信相对比较简单。

    当需要有多个线程来访问一个全局变量时,通常我们会在这个全局变量前加上volatile声明,来告诉编译器这个全局变量是“易变”(更直接的讲是“直接存取原始内存地址”,更明确的说是不要编辑器去读缓存中的数据,而是直接从内存中获取变量的值)的,让编译器不要对这个变量进行优化。

    使用多线程相对于多进程来说有很多优点:

    • ① 无需跨进程边界;
    • ② 程序逻辑和控制方式简单;
    • ③ 所有线程可以直接共享内存和变量等;
    • ④ 线程方式消耗的总资源比进程方式好;

       

    多线程通信的方法主要有以下三种: 

    1.全局变量

    由于同一进程下的线程之间共享数据空间。当需要有多个线程来访问一个全局变量时,通常我们会在这个全局变量前加上volatile声明,以防编译器对此变量进行优化。

    2.Message消息机制
    常用的Message通信的接口主要有两个:PostMessage和PostThreadMessage,
    PostMessage为线程向主窗口发送消息。而PostThreadMessage是任意两个线程之间的通信接口。

    PostMessage() 
    函数原型:
        B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);

    参数:
        hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:
        HWND.BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口
    和弹出式窗口。消息不被寄送到子窗口。
        NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样。
        Msg:指定被寄送的消息。
        wParam:指定附加的消息特定的信息。
        IParam:指定附加的消息特定的信息。
        返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。
    MS还提供了SendMessage方法进行消息间通讯,SendMessage(),他和PostMessage的区别是:

    SendMessage是同步的,而PostMessage是异步的。SendMessage必须等发送的消息执行之后,才返回。
    PostThreadMessage()

    PostThreadMessage方法可以将消息发送到指定线程。
    函数原型:BOOL PostThreadMessage(DWORD idThread,UINT Msg,WPARAM wParam, LPARAM lParam);

    参数除了ThreadId之外,基本和PostMessage相同。
    目标线程通过GetMessage()方法来接受消息。

    注:使用这个方法时,目标线程必须已经有自己的消息队列。否则会返回ERROR_INVALID_THREAD_ID错误。可以用
    PeekMessage()给线程创建消息队列。

    3.CEvent对象

    CEvent为MFC中的一个对象,可以通过对CEvent的触发状态进行改变,从而实现线程间的通信和同步,这个主要是实现线程直接同步的一种方法。

    ************************************************************************

    Linux 多线程通信

    摘自资料(linux 与Windows不同)

         线程间无需特别的手段进行通信,因为线程间可以共享数据结构,也就是一个全局变量可以被两个线程同时使用。不过要注意的是线程间需要做好同步,一般用mutex。可以参考一些比较新的UNIX/Linux编程的书,都会提到Posix线程编程,比如《UNIX环境高级编程(第二版)》、《UNIX系统编程》等等。 linux的消息属于IPC,也就是进程间通信,线程用不上。

    linux用pthread_kill对线程发信号。 另:windows下不是用post..(你是说PostMessage吗?)进行线程通信的吧?

    windows用PostThreadMessage进行线程间通信,但实际上极少用这种方法。还是利用同步多一些 LINUX下的同步和Windows原理都是一样的。不过Linux下的singal中断也很好用。

    用好信号量,共享资源就可以了。

     使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。

      使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。
    1、简单的多线程程序

       首先在主函数中,我们使用到了两个函数,pthread_create和pthread_join,并声明了一个pthread_t型的变量。
    pthread_t在头文件pthread.h中已经声明,是线程的标示符

       函数pthread_create用来创建一个线程,函数原型:

    extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t*__attr,void *(*__start_routine) (void *), void *__arg));

      第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。若我们的函数thread不需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空指针,这样将生成默认属性的线程。对线程属性的设定和修改我们将在下一节阐述。当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。

    函数pthread_join用来等待一个线程的结束。函数原型为:

      extern int pthread_join __P ((pthread_t __th, void **__thread_return));

      第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit来实现。它的函数原型为:

      extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));

      唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给thread_return。最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。

    2、修改线程的属性
    设置线程绑定状态的函数为pthread_attr_setscope,它有两个参数,第一个是指向属性结构的指针,第二个是绑定类型,它有两个取值:PTHREAD_SCOPE_SYSTEM(绑定的)和PTHREAD_SCOPE_PROCESS(非绑定的)。下面的代码即创建了一个绑定的线程。

    #include 
    pthread_attr_t attr;
    pthread_t tid;

    /*初始化属性值,均设为默认值*/
    pthread_attr_init(&attr);
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

    pthread_create(&tid, &attr, (void *) my_function, NULL);

    3、线程的数据处理

    和进程相比,线程的最大优点之一是数据的共享性,各个进程共享父进程处沿袭的数据段,可以方便的获得、修改数据。但这也给多线程编程带来了许多问题。我们必须当心有多个不同的进程访问相同的变量。许多函数是不可重入的,即同时不能运行一个函数的多个拷贝(除非使用不同的数据段)。在函数中声明的静态变量常常带来问题,函数的返回值也会有问题。因为如果返回的是函数内部静态声明的空间的地址,则在一个线程调用该函数得到地址后使用该地址指向的数据时,别的线程可能调用此函数并修改了这一段数据。在进程中共享的变量必须用关键字volatile来定义,这是为了防止编译器在优化时(如gcc中使用-OX参数)改变它们的使用方式。为了保护变量,我们必须使用信号量、互斥等方法来保证我们对变量的正确使用。

    4、互斥锁

    互斥锁用来保证一段时间内只有一个线程在执行一段代码。必要性显而易见:假设各个线程向同一个文件顺序写入数据,最后得到的结果一定是灾难性的


    展开全文
  • 多进程和多线程之间的通信方式及通信实现步骤小结

    进程间通信方式

    # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

    # 有名管道 (namedpipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

    # 高级管道(popen):将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。

    # 信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

    # 消息队列( messagequeue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

    # 信号 ( sinal ) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

    # 共享内存( sharedmemory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。

    # 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

    Socket通信实现步骤:

    8.1命名socket

    SOCK_STREAM 式本地套接字的通信双方均需要具有本地地址,其中服务器端的本地地址需要明确指定,指定方法是使用 struct sockaddr_un 类型的变量。

    8.2 绑定

    SOCK_STREAM 式本地套接字的通信双方均需要具有本地地址,其中服务器端的本地地址需要明确指定,指定方法是使用 struct sockaddr_un 类型的变量,将相应字段赋值,再将其绑定在创建的服务器套接字上,绑定要使用 bind 系统调用,其原形如下:

    intbind(intsocket, const struct sockaddr *address, size_t address_len);

    其中 socket表示服务器端的套接字描述符,address 表示需要绑定的本地地址,是一个 struct sockaddr_un 类型的变量,address_len 表示该本地地址的字节长度。

    8.3 监听

    服务器端套接字创建完毕并赋予本地地址值(名称,本例中为Server Socket)后,需要进行监听,等待客户端连接并处理请求,监听使用 listen 系统调用,接受客户端连接使用accept系统调用,它们的原形如下:

    intlisten(intsocket, int backlog);

    intaccept(intsocket, struct sockaddr *address, size_t *address_len);

    其中 socket 表示服务器端的套接字描述符;backlog 表示排队连接队列的长度(若有多个客户端同时连接,则需要进行排队);address 表示当前连接客户端的本地地址,该参数为输出参数,是客户端传递过来的关于自身的信息;address_len 表示当前连接客户端本地地址的字节长度,这个参数既是输入参数,又是输出参数。

    8.4 连接服务器

    客户端套接字创建完毕并赋予本地地址值后,需要连接到服务器端进行通信,让服务器端为其提供处理服务。

    对于SOCK_STREAM类型的流式套接字,需要客户端与服务器之间进行连接方可使用。连接要使用 connect 系统调用,其原形为

    intconnect(intsocket, const struct sockaddr *address, size_t address_len);

    其中socket为客户端的套接字描述符,address表示当前客户端的本地地址,是一个 struct sockaddr_un 类型的变量,address_len 表示本地地址的字节长度。实现连接的代码如下:

    connect(client_sockfd,(struct sockaddr*)&client_address, sizeof(client_address));

    8.5 相互发送接收数据

    无论客户端还是服务器,都要和对方进行数据上的交互,这种交互也正是我们进程通信的主题。一个进程扮演客户端的角色,另外一个进程扮演服务器的角色,两个进程之间相互发送接收数据,这就是基于本地套接字的进程通信。发送和接收数据要使用 write 和 read 系统调用,它们的原形为:

    intread(intsocket, char *buffer, size_t len);

    intwrite(intsocket, char *buffer, size_t len);

    其中 socket 为套接字描述符;len 为需要发送或需要接收的数据长度;

    对于 read 系统调用,buffer 是用来存放接收数据的缓冲区,即接收来的数据存入其中,是一个输出参数;

    对于 write 系统调用,buffer 用来存放需要发送出去的数据,即 buffer 内的数据被发送出去,是一个输入参数;返回值为已经发送或接收的数据长度。

    8.6 断开连接

    交互完成后,需要将连接断开以节省资源,使用close系统调用,其原形为:

    intclose(intsocket);

    线程间通信方式

    # 锁机制:包括互斥锁、条件变量、读写锁

       *互斥锁提供了以排他方式防止数据结构被并发修改的方法。

       *读写锁允许多个线程同时读共享数据,而对写操作是互斥的。

       *条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。

    # 信号量机制(Semaphore):包括无名线程信号量和命名线程信号量

    # 信号机制(Signal):类似进程间的信号处理

    线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。

    多线程通信的方法主要有以下三种:

    1.全局变量

    进程中的线程间内存共享,这是比较常用的通信方式和交互方式。

    注:定义全局变量时最好使用volatile来定义,以防编译器对此变量进行优化。

    2.Message消息机制

    常用的Message通信的接口主要有两个:PostMessage和PostThreadMessage,

    PostMessage为线程向主窗口发送消息。而PostThreadMessage是任意两个线程之间的通信接口。

    2.1.PostMessage()

    函数原型:

    B00L PostMessage(HWND hWnd,UINT Msg,WPARAMwParam,LPARAM lParam);

    参数:

    hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:

    HWND.BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口

    和弹出式窗口。消息不被寄送到子窗口。

    NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样。

    Msg:指定被寄送的消息。

    wParam:指定附加的消息特定的信息。

    IParam:指定附加的消息特定的信息。

    返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。

    MS还提供了SendMessage方法进行消息间通讯,SendMessage(),他和PostMessage的区别是:

    SendMessage是同步的,而PostMessage是异步的。SendMessage必须等发送的消息执行之后,才返回。

    2.2.PostThreadMessage(

    PostThreadMessage方法可以将消息发送到指定线程。

    函数原型:BOOLPostThreadMessage(DWORD idThread,UINT Msg,WPARAM wParam, LPARAM lParam);

    参数除了ThreadId之外,基本和PostMessage相同。

    目标线程通过GetMessage()方法来接受消息。

    注:使用这个方法时,目标线程必须已经有自己的消息队列。否则会返回ERROR_INVALID_THREAD_ID错误。可以用

    PeekMessage()给线程创建消息队列。

    3.CEvent对象

    CEvent为MFC中的一个对象,可以通过对CEvent的触发状态进行改变,从而实现线程间的通信和同步。

    展开全文
  • JAVA多线程之线程间的通信方式

    千次阅读 2019-06-18 16:21:52
    本总结我对于JAVA多线程中线程之间的通信方式的理解,主要以代码结合文字的方式来讨论线程间的通信,故摘抄了书中的一些示例代码。 二,线程间的通信方式 ①同步 这里讲的同步是指多个线程通过synchronized...

    一,介绍

    本总结我对于JAVA多线程中线程之间的通信方式的理解,主要以代码结合文字的方式来讨论线程间的通信,故摘抄了书中的一些示例代码。

     

    二,线程间的通信方式

    ①同步

    这里讲的同步是指多个线程通过synchronized关键字这种方式来实现线程间的通信。

    参考示例:

    由于线程A和线程B持有同一个MyObject类的对象object,尽管这两个线程需要调用不同的方法,但是它们是同步执行的,比如:线程B需要等待线程A执行完了methodA()方法之后,它才能执行methodB()方法。这样,线程A和线程B就实现了 通信。

    这种方式,本质上就是“共享内存”式的通信。多个线程需要访问同一个共享变量,谁拿到了锁(获得了访问权限),谁就可以执行。

     

    ②while轮询的方式

    代码如下:

    在这种方式下,线程A不断地改变条件,线程ThreadB不停地通过while语句检测这个条件(list.size()==5)是否成立 ,从而实现了线程间的通信。但是这种方式会浪费CPU资源。之所以说它浪费资源,是因为JVM调度器将CPU交给线程B执行时,它没做啥“有用”的工作,只是在不断地测试 某个条件是否成立。就类似于现实生活中,某个人一直看着手机屏幕是否有电话来了,而不是: 在干别的事情,当有电话来时,响铃通知TA电话来了。关于线程的轮询的影响,可参考:JAVA多线程之当一个线程在执行死循环时会影响另外一个线程吗?

    这种方式还存在另外一个问题:

    轮询的条件的可见性问题,关于内存可见性问题,可参考:JAVA多线程之volatile 与 synchronized 的比较中的第一点“一,volatile关键字的可见性

    线程都是先把变量读取到本地线程栈空间,然后再去再去修改的本地变量。因此,如果线程B每次都在取本地的 条件变量,那么尽管另外一个线程已经改变了轮询的条件,它也察觉不到,这样也会造成死循环。

    ③wait/notify机制

    代码如下:

    线程A要等待某个条件满足时(list.size()==5),才执行操作。线程B则向list中添加元素,改变list 的size。

    A,B之间如何通信的呢?也就是说,线程A如何知道 list.size() 已经为5了呢?

    这里用到了Object类的 wait() 和 notify() 方法。

    当条件未满足时(list.size() !=5),线程A调用wait() 放弃CPU,并进入阻塞状态。---不像②while轮询那样占用CPU

    当条件满足时,线程B调用 notify()通知 线程A,所谓通知线程A,就是唤醒线程A,并让它进入可运行状态。

    这种方式的一个好处就是CPU的利用率提高了。

    但是也有一些缺点:比如,线程B先执行,一下子添加了5个元素并调用了notify()发送了通知,而此时线程A还执行;当线程A执行并调用wait()时,那它永远就不可能被唤醒了。因为,线程B已经发了通知了,以后不再发通知了。这说明:通知过早,会打乱程序的执行逻辑。

     

    ④管道通信就是使用java.io.PipedInputStream 和 java.io.PipedOutputStream进行通信

    具体就不介绍了。分布式系统中说的两种通信机制:共享内存机制和消息通信机制。感觉前面的①中的synchronized关键字和②中的while轮询 “属于” 共享内存机制,由于是轮询的条件使用了volatile关键字修饰时,这就表示它们通过判断这个“共享的条件变量“是否改变了,来实现进程间的交流。

    而管道通信,更像消息传递机制,也就是说:通过管道,将一个线程中的消息发送给另一个。

    展开全文
  • java的多线程通信有Lock,wait/notify,Semaphore三种方式,已一道常见面试题来简单演示这三种多线程通信方式。 两个线程循环间隔打印指定内容,一个打印从1到52的数字,一个打印从A到Z的字母,打印输出如下: 1 2 A...
  • C++多线程,多线程通信,队列

    千次阅读 2019-06-25 19:19:18
    条件变量std::condition_variable用于多线程之间的通信,它可以阻塞一个或同时阻塞多个线程。std::condition_variable需要与std::unique_lock配合使用。std::condition_variable效果上相当于包装了pthread库中的...
  • Qt多线程通信

    万次阅读 多人点赞 2018-03-03 11:56:03
    1> Qt线程间共享数据主要有两种方式: 1)使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的。 2)使用singal/slot机制,把数据...
  • 采用全局变量方式实现多线程通信:用一个全局变量来控制时间显示线程的时间显示格式,比较简单,仅供参考和学习,欢迎大家多多交流。
  • 多线程与多进程通信方式的区别

    千次阅读 2017-02-07 22:56:31
    多线程与多进程通信方式的区别? 1) 在数据共享同步方面:多进程数据共享复杂,需要IPC;数据是分开的,同步简单;多线程共享数据简单,但是同步复杂。 2) 内存方面:多进程占有内存多,切换复杂,CPU利用率低;...
  • 多线程线程通信wait和notify的使用

    千次阅读 2018-06-20 09:26:46
    线程通信
  • 多线程线程通信

    万次阅读 2018-02-28 15:56:33
    http://blog.csdn.net/jiazhen/article/details/1611721简介 线程之间通信的两个基本问题是互斥和同步。 线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程...
  • 多线程串口通信

    千次阅读 2017-04-27 15:02:16
    多线程实现串口通信 备注:用了刘大师的“QT多线程示例+一种通用高并发数据处理最简单思路”思路,在模仿刘大师的基础上增加了串口通信功能; 截图如下: 说明: 1、线程数量:3(GUI、串口...
  • 多线程之间通信的5种方式

    千次阅读 2020-01-05 15:11:39
    首先,我们知道线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的;...众所周知,Object类提供了线程间通信的方法:wait()、notify()、notifyaAl(),它们是多线程通信的基础,而这...
  • Qt线程间共享数据主要有两种方式: 1)使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的。 2)使用singal/slot机制,把数据从一个...
  • QT C++ 多线程支持多串口通信,实现了串口的基本功能,和多线程框架,C++编写,全部工程文件已压缩
  • 线程通信方式3:消息传递方式

    热门讨论 2013-01-18 11:01:23
    线程间通信方式3:消息传递方式的演示。采用计算演示线程的执行,并采用用户界面线程来实时显示执行的进度,线程间的通信方式采用了3种方式相结合,对多线程间的通信有比较好的学习和研究价值。
  • linux下多线程通信(一)

    万次阅读 2018-09-21 20:11:57
    在linux下进行多线程编程,肯定会涉及到线程通信问题,本文主要分析pipe,即管道在多线之间通信实现。 #include<unistd.h> int pipe(int filedes[2]); 返回值:成功...
  • 包括TCP服务器客户端多线程通信程序(用select实现),基于Visual Studio2017实现,已编译测试过,用到的朋友记得关闭SDL检查
  • 进程与线程的区别进程的通信方式线程通信方式 进程与线程的区别: 通俗的解释 一个系统运行着很进程,可以比喻为一条马路上有很马车 不同的进程可以理解为不同的马车 而同一辆马车可以有很匹马来拉--...
  • Java多线程以及进程间的通信方式

    千次阅读 2018-03-22 20:22:28
    Java 线程通信:1共享变量,如volatite等2wait/notify机制,最好搭配同步锁3Lock/Condition机制 //condition.await();condition.signalAll();4管道 //PipedOutputStream out; PipedInputStream in; out....
  • Android多线程通信机制

    千次阅读 2018-08-07 16:48:58
    掌握Android的多线程通信机制,我们首先应该掌握Android中进程与线程是什么。 1. 进程 在Android中,一个应用程序就是一个独立的进程(应用运行在一个独立的环境中,可以避免其他应用程序/进程的干扰)。一般来说...
  • java实现线程通信的几种方式

    千次阅读 2020-05-30 19:34:35
    比如大家熟知的消息中间件的实现,从某种角度上讲,就借助了多线程通信的思想,下面总结了JDK中常用的几种实现线程通信的方式,提供参考 1、synchronized实现方式 可能很多小伙伴们会有疑问,synchronized是对共享...
  • 线程通信方式2:参数传递方式

    热门讨论 2013-01-11 11:17:13
    线程通信方式2:参数传递方式。通过3类线程的创建方法,演示了给线程传递方式的方式,包括;单参数、参数和类3类。
  • Linux 多线程通信

    万次阅读 2008-03-13 11:01:00
    摘自资料(linux 与Windows不同) 线程间无需特别的手段进行通信,因为线程间可以共享数据结构,也就是一个全局变量可以被两个线程同时使用。不过要注意的是线程间需要做好同步,一般用mutex。可以参考一些比较新的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 427,366
精华内容 170,946
关键字:

多线程通信方式