精华内容
下载资源
问答
  • 阻塞等待线程启动一、 应用场景 1. 子线程创建后不主动退出,主线程不能使用pthread_join被动等待子线程结束。 2. 主线程创建子线程之后,后续业务逻辑的处理依赖于子线程中的业务处理状态。二、代码实现代码块...

    阻塞等待线程启动

    一、 应用场景
    1. 子线程创建后不主动退出,主线程不能使用pthread_join被动等待子线程结束。
    2. 主线程创建子线程之后,后续业务逻辑的处理依赖于子线程中的业务处理状态。

    二、代码实现

    代码块(主线程)
    #define nthreads 10          // 子线程个数
    static int  init_count =  0; // 已启动的子线程个数
    static pthread_mutex_t   lock = PTHREAD_MUTEX_INITIALIZER;
    static pthread_cond_t    cond = PTHREAD_COND_INITIALIZER;
    pthread_t thread_id[nthreads];
    
    void* thread_cb(void*); // 子线程callback声明
    
    for (int i = 0; i < nthreads; i++) {
        pthread_create(&thread_id[i], NULL, thread_cb, NULL);
    }
    pthread_mutex_lock (&lock);
    while (init_count < nthreads) {
        pthread_cond_wait(&cond, &lock);
    }
    pthread_mutex_unlock(&lock);
    代码块(子线程回调)
    void*
    thread_cb(void *arg)
    {
        /*
            do something
        */
        pthread_mutex_lock(&lock);
        init_count++;
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&lock);
    
        while(1) {
            // do something work
        }; 
        return NULL;
    }

    三、总结
    代码本身是一种生产-消费模型的基本应用。
    主线程可以认为是生产者,相应的消费者即是子线程。
    生产完成后利用pthread_cond_wait等待消费者的处理状态消息。
    那么有个老生常谈的问题:
    pthread_cond_signal 的调用是不是一定要先加锁再解锁?
    YES, 一定要在{lock, unlock}块中。


    展开全文
  • linux 线程等待队列

    千次阅读 2013-05-09 20:14:36
    假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。 如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但无论如何一个...

    pthread_cond_signal不会有“惊群现象”产生,他最多只给一个线程发信号
    假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。
    如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但无论如何一个pthread_cond_signal调用最多发信一次。

    pthread_cond_wait必须放在pthread_mutex_lock和pthread_mutex_unlock之间,因为他要根据共享变量的状态来决定是否要等待,而为了不永远等待下去所以必须要在lock/unlock队中
    例如:pthread_mutex_lock(&alsa_params->playback_mutex);
     
        while( !alsa_params->wait_flag ) 
        {
            adec_print("yvonnepthread_cond_wait\n");
             pthread_cond_wait(&alsa_params->playback_cond, &alsa_params->playback_mutex);
        }
        alsa_params->wait_flag=1;
        pthread_mutex_unlock(&alsa_params->playback_mutex);

    pthread_cond_signal即可以放在pthread_mutex_lock和pthread_mutex_unlock之间,也可以放在pthread_mutex_lock和pthread_mutex_unlock之后,但是各有各缺点 
     pthread_mutex_lock(&alsa_param->playback_mutex);
        alsa_param->wait_flag=1;//yvonneadded
        pthread_cond_signal(&alsa_param->playback_cond);
        pthread_mutex_unlock(&alsa_param->playback_mutex);
     
    在Linux 线程中,有两个队列,分别是cond_wait队列和mutex_lock队列, cond_signal只是让线程从cond_wait队列移到mutex_lock队列,而不用返回到用户空间,不会有性能的损耗

    JNIEXPORT jint
    JNI_OnLoad(JavaVM* vm, void* reserved)
    {
        jint ret;
        JNIEnv* env = NULL;
       if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK || NULL == env) {
            return -1;
        }
     fields.gJavaVM = vm;
        fields.env = env; 在onload时候保存下来jvm和env,
      ret = register_amplayer_amavjni(env);

    struct fields_t {
        JavaVM      *gJavaVM ;
        JNIEnv* env;
        jmethodID   post_event;
    };
    static struct fields_t fields;

    JNIEnv 指针一样,jobject指针也不能在多个线程中共享.
     就是说,不能直接在保存一个线程中的jobject指针到全局变量中,然后在另外一个线程中使用它
     player->mClass = (jclass)env->NewGlobalRef(clazz);
     env->DeleteGlobalRef(player->mObject);
     //初始化时指定post_event
     fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                "(Ljava/lang/Object;IIILjava/lang/Object;)V");
     在postEventFromNative调用   
     amavjni mp = (amavjni) ((WeakReference<Object>) mediaplayer_ref).get();
     mp.handle_events(what, arg1, arg2);
     if (monStateChangeLisenser != null)
       monStateChangeLisenser.StateChanged(what, arg1, arg2);//StateChanged提供子类实现
       
       
    #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)__VA_ARGS__ 成不定参数

    展开全文
  • 线程等待: 函数:pthread_join extern int pthread_join __P (pthread_t __th, void **__thread_return);...这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待

    线程等待

    函数:pthread_join

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

    参数:
    第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。

    这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。


    返回值:

    如果执行成功,将返回0,如果失败则返回一个错误号。  

     


    线程终止

    函数:pthread_exit

    void pthread_exit(void* retval);  

     

    参数

    retval是一个无类型指针,与传给启动例程的单个参数类似。

    同一进程中的其他线程可调用pthread_join函数访问这个指针。调用了pthread_join的线程会一直阻塞直到它指定的线程调用pthread_exit、从启动例程中返回或者被取消。

    如果线程从启动它的例程返回,retval将包含返回码。若线程被取消则retval指定的内存空间会被置为PTHREAD_CANCELED。

     

    函数功能:线程通过调用pthread_exit函数终止执行,就如同进程在结束时调用exit函数一样。

    这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针。


    代码说明:

    /*
    pthread_join, pthread_exit
    17.11.28
    */
    
    #include <stdio.h>
    #include <pthread.h>
    #include <errno.h>
    
    void * Pthreadfunc1()
    {
        printf("I am pthread\n");
        
        pthread_exit((void*)1);  //线程退出
    }
    
    int main(int argc, char * argv [ ])
    {
        int iRet = 0;
        void *rval = NULL;
        pthread_t pid1;
    
        iRet = pthread_create(&pid1, NULL, Pthreadfunc1, NULL);     //创建一个线程pthreadfunc1
        if(0 != iRet)
        {
            printf("pthread_create error, %s,%d\n", (char *)strerror(errno), errno);
            return -1;
        }
    
        pthread_join(pid1, &rval);  //线程等待,线程退出的值存放在rval中
        printf("rval= %d\n", (int)rval);
        
        return 0;
    }
    代码进行编译:

    gcc pthread_join.c -lpthread -o pthread_join

    代码运行:

    ./pthread_join


    运行结果:

    I am pthread
    rval= 1


    分析:1:调用了pthread_join函数后,阻塞了后面代码的运行

    2:线程调用pthread_exit函数退出后,返回码存储在了pthread_join的第二个参数中。

    3:pthread_join等待的线程结束后,接着往下执行代码,所以printf进行打印。



    展开全文
  • * 单线程/多线程阻塞I/O模型 * 单线程非阻塞I/O模型 * 多线程非阻塞I/O模型,Reactor及其改进 前言 这里探讨的服务器模型主要指的是服务器端对I/O的处理模型。从不同维度可以有不同的分类,这里从I/O的阻塞与...

    前言的前言

    服务器模型涉及到线程模式和IO模式,搞清楚这些就能针对各种场景有的放矢。该系列分成三部分:
    * 单线程/多线程阻塞I/O模型
    * 单线程非阻塞I/O模型
    * 多线程非阻塞I/O模型,Reactor及其改进

    前言

    这里探讨的服务器模型主要指的是服务器端对I/O的处理模型。从不同维度可以有不同的分类,这里从I/O的阻塞与非阻塞、I/O处理的单线程与多线程角度探讨服务器模型。

    对于I/O,可以分成阻塞I/O与非阻塞I/O两大类型。阻塞I/O在做I/O读写操作时会使当前线程进入阻塞状态,而非阻塞I/O则不进入阻塞状态。

    对于线程,单线程情况下由一条线程负责所有客户端连接的I/O操作,而多线程情况下则由若干线程共同处理所有客户端连接的I/O操作。

    单线程非阻塞I/O模型

    多线程阻塞I/O模型通过引入多线程确实提高了服务器端的并发处理能力,但每个连接都需要一个线程负责I/O操作。当连接数量较多时可能导致机器线程数量太多,而这些线程大多数时间却处于等待状态,造成极大的资源浪费。鉴于多线程阻塞I/O模型的缺点,有没有可能用一个线程就可以维护多个客户端连接并且不会阻塞在读写操作呢?下面介绍单线程非阻塞I/O模型。

    单线程非阻塞I/O模型最重要的一个特点是,在调用读取或写入接口后立即返回,而不会进入阻塞状态。在探讨单线程非阻塞I/O模型前必须要先了解非阻塞情况下套接字事件的检测机制,因为对于单线程非阻塞模型最重要的事情是检测哪些连接有感兴趣的事件发生。一般会有如下三种检测方式。

    应用程序遍历套接字的事件检测

    当多个客户端向服务器请求时,服务器端会保存一个套接字连接列表中,应用层线程对套接字列表轮询尝试读取或写入。对于读取操作,如果成功读取到若干数据,则对读取到的数据进行处理;如果读取失败,则下一个循环再继续尝试。对于写入操作,先尝试将数据写入指定的某个套接字,写入失败则下一个循环再继续尝试。

    这里写图片描述

    这样看来,不管有多少个套接字连接,它们都可以被一个线程管理,一个线程负责遍历这些套接字列表,不断地尝试读取或写入数据。这很好地利用了阻塞的时间,处理能力得到提升。但这种模型需要在应用程序中遍历所有的套接字列表,同时需要处理数据的拼接,连接空闲时可能也会占用较多CPU资源,不适合实际使用。对此改进的方法是使用事件驱动的非阻塞方式。

    内核遍历套接字的事件检测

    这种方式将套接字的遍历工作交给了操作系统内核,把对套接字遍历的结果组织成一系列的事件列表并返回应用层处理。对于应用层,它们需要处理的对象就是这些事件,这就是其中一种事件驱动的非阻塞方式的实现。

    服务器端有多个客户端连接,应用层向内核请求读写事件列表。内核遍历所有套接字并生成对应的可读列表readList和可写列表writeList。readList标明了每个套接字是否可读,例如套接字1的值为1,表示可读,socket2的值为0,表示不可读。writeList则标明了每个套接字是否可写。应用层遍历读写事件列表readList和writeList,做相应的读写操作。

    这里写图片描述

    内核遍历套接字时已经不用在应用层对所有套接字进行遍历,将遍历工作下移到内核层,这种方式有助于提高检测效率。然而,它需要将所有连接的可读事件列表和可写事件列表传到应用层,假如套接字连接数量变大,列表从内核复制到应用层也是不小的开销。另外,当活跃连接较少时,内核与应用层之间存在很多无效的数据副本,因为它将活跃和不活跃的连接状态都复制到应用层中。

    内核基于回调的事件检测

    通过遍历的方式检测套接字是否可读可写是一种效率比较低的方式,不管是在应用层中遍历还是在内核中遍历。所以需要另外一种机制来优化遍历的方式,那就是回调函数。内核中的套接字都对应一个回调函数,当客户端往套接字发送数据时,内核从网卡接收数据后就会调用回调函数,在回调函数中维护事件列表,应用层获取此事件列表即可得到所有感兴趣的事件。

    内核基于回调的事件检测方式有两种。第一种是用可读列表readList和可写列表writeList标记读写事件,套接字的数量与readList和writeList两个列表的长度一样,readList第一个元素标为1则表示套接字1可读,同理,writeList第二个元素标为1则表示套接字2可写。如图所示,多个客户端连接服务器端,当客户端发送数据过来时,内核从网卡复制数据成功后调用回调函数将readList第一个元素置为1,应用层发送请求读、写事件列表,返回内核包含了事件标识的readList和writeList事件列表,进而分表遍历读事件列表readList和写事件列表writeList,对置为1的元素对应的套接字进行读或写操作。这样就避免了遍历套接字的操作,但仍然有大量无用的数据(状态为0的元素)从内核复制到应用层中。于是就有了第二种事件检测方式。

    这里写图片描述

    内核基于回调的事件检测方式二如图所示。服务器端有多个客户端套接字连接。首先,应用层告诉内核每个套接字感兴趣的事件。接着,当客户端发送数据过来时,对应会有一个回调函数,内核从网卡复制数据成功后即调回调函数将套接字1作为可读事件event1加入到事件列表。同样地,内核发现网卡可写时就将套接字2作为可写事件event2添加到事件列表中。最后,应用层向内核请求读、写事件列表,内核将包含了event1和event2的事件列表返回应用层,应用层通过遍历事件列表得知套接字1有数据待读取,于是进行读操作,而套接字2则可以写入数据。

    这里写图片描述

    上面两种方式由操作系统内核维护客户端的所有连接并通过回调函数不断更新事件列表,而应用层线程只要遍历这些事件列表即可知道可读取或可写入的连接,进而对这些连接进行读写操作,极大提高了检测效率,自然处理能力也更强。

    对于Java来说,非阻塞I/O的实现完全是基于操作系统内核的非阻塞I/O,它将操作系统的非阻塞I/O的差异屏蔽并提供统一的API,让我们不必关心操作系统。JDK会帮我们选择非阻塞I/O的实现方式,例如对于Linux系统,在支持epoll的情况下JDK会优先选择用epoll实现Java的非阻塞I/O。这种非阻塞方式的事件检测机制就是效率最高的“内核基于回调的事件检测”中的第二种方式。

    在了解了非阻塞模式下的事件检测方式后,重新回到对单线程非阻塞I/O模型的讨论。虽然只有一个线程,但是它通过把非阻塞读写操作与上面几种检测机制配合就可以实现对多个连接的及时处理,而不会因为某个连接的阻塞操作导致其他连接无法处理。在客户端连接大多数都保持活跃的情况下,这个线程会一直循环处理这些连接,它很好地利用了阻塞的时间,大大提高了这个线程的执行效率。

    单线程非阻塞I/O模型的主要优势体现在对多个连接的管理,一般在同时需要处理多个连接的发场景中会使用非阻塞NIO模式,此模型下只通过一个线程去维护和处理连接,这样大大提高了机器的效率。一般服务器端才会使用NIO模式,而对于客户端,出于方便及习惯,可使用阻塞模式的套接字进行通信。

    =============广告时间===============

    公众号的菜单已分为“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。

    鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以购买。感谢各位朋友。

    为什么写《Tomcat内核设计剖析》

    =========================

    欢迎关注:

    这里写图片描述

    展开全文
  • Linux线程

    千次阅读 2019-04-23 15:43:32
    Linux线程_01线程介绍和常用系统调用1.Linux线程1.1进程回顾1.2程序并发的时空开销1.3线程的的特点2.POSIX线程常用系统调用2.1线程创建与回收2.2线程取消2.3线程函数退出相关2.4获取线程id 1.Linux线程 如果说在操作...
  • Linux C 线程等待

    万次阅读 2013-10-08 19:47:13
      ...linux 下面的sleep,usleep,nanosleep 和select比较 sleep 时间单位是秒 usleep的时间单位是微秒 select的精度是微妙,精确 struct timeval delay; delay.tv_
  • linux线程编程中,如果线程A创建了线程B,我知道用pthread__ join可以令线程A 阻塞然后等待线程B的退出。如果线程A创建了三个线程B,C,D,执行完的先后顺序不知。想让A必须等待三个线程都退出后再退出,应该怎么做...
  • Linux驱动阻塞与非阻塞IO之等待队列

    千次阅读 2012-03-22 20:42:17
    上次我和大家一起探讨了Linux驱动中的竞态问题,本环节为们来探讨一下Linux 驱动编写中的阻塞与非阻塞I/O 阻塞与非阻塞I/O简介 阻塞操作:是指在执行设备操作时,若不能获得资源,则挂起进程...
  • Linux 线程浅析

    千次阅读 2015-04-14 14:53:28
    进程和线程的区别与联系 在许多经典的操作系统教科书中,总是把进程定义为程序的执行实例,它并不执行什么, 只是维护应用程序所需的各种资源,而线程则是真正的执行实体。 为了让进程完成一定的工作,进程必须至少...
  • linux线程及线程同步(锁的应用)

    千次阅读 2018-06-08 15:36:33
    linux线程 linux原本没有线程,后来在windows多线程编程影响下linux内核开发者在进程基础上在功能上做出了类似windows线程的linux版本的线程,linux线程归根到底还是进程,只不过是轻量级的进程,开销比真正进程...
  • 接下来我们看一下线程退出函数和等待函数。  #include  void pthread_exit(void *value_ptr); value_ptr:是线程的返回值。有pthread_join()检测获得。 功能:线程退出 #include  int pthread_join(pthread...
  • Linux线程同步

    千次阅读 2020-03-06 09:20:48
    文章目录一、线程同步的概念二、互斥锁1、初始化锁2、阻塞加锁3、非阻塞加锁4、解锁5、销毁锁(此时锁必需unlock状态,否则返回EBUSY)三、示例程序四、版权声明 一、线程同步的概念 线程同步?怎么同步?一起运行?...
  • 有关线程中断和线程阻塞

    千次阅读 2014-05-24 15:49:30
    一个线程都要从运行到结束都要经过3个阶段: 1、正在运行 2、准备结束运行 3、结束运行 那么怎么结束这个线程呢?可以通过下面这三个方法结束一个线程。 1、使用stop()方法强制结束线程。 2、使用thread....
  • 认识linux 线程

    千次阅读 2017-08-09 20:27:35
    线程定义:线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必...
  • 1. 什么是线程   线程是进程执行内部的一个执行分支,在一个进程内部运行的多种执行流;内部本质上是多个线程在同一个地址空间运行;第一个pcb称之为主线程;有多个线程就有多个执行流;一个进程至少有一个线程 ...
  • linux机器cpu核数等于8  一、分析原因  1、单线程进行es数据召回,耗时30ms左右,猜猜是由于多线程导致的  2、切回线程池多线程执行es数据召回,每条数据耗时1000ms左右,此时线程池配置如下:  private...
  • pid:所等待线程ID; value_ptr:通常设置为NULL,如果不为NULL,pthread_join将复制一份线程退出值到一个内存区域,并让*value_ptr指向该内存。 返回值:执行成功返回0,否则返回错误码。 2、作用 pthread_...
  • linux线程同步的方法

    千次阅读 2018-04-13 15:30:06
    Linux 线程同步的三种方法 线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点。linux下提供了多种方式来处理线程同步,最常用的是互斥锁、条件变量和信号量。 一、互斥锁(mutex) ...
  • linux线程浅析

    千次阅读 2013-05-11 16:25:07
    关于linux线程  在许多经典的操作系统教科书中, 总是把进程定义为程序的执行实例, 它并不执行什么, 只是维护应用程序所需的各种资源. 而线程则是真正的执行实体. 为了让进程完成一定的工作, 进程必须至少包含...
  • LinuxLinux线程技术

    万次阅读 2018-09-05 15:57:23
    Linux线程概念 线程的概念 线程是计算机科学中的一个术语,是指运行中的程序的调度单位。一个线程指的是进程中一个单一顺序的控制流,也称为轻量进程。它是系统独立调度和分配的基本单位。同一进程中的多个线程...
  • linux下的C语言开发(线程等待)

    千次阅读 2016-07-06 21:48:20
    线程等待
  • Linux线程详解

    万次阅读 多人点赞 2019-06-03 12:06:33
    pthread_join函数 阻塞等待线程退出,获取线程退出状态 其作用,对应进程中 waitpid() 函数。 int pthread_join(pthread_t thread, void **retval); 成功:0;失败:错误号 参数:thread:线程ID (【注意】...
  • Linux 线程锁详解

    千次阅读 2018-11-08 00:50:54
    Linux 线程锁详解
  • Linux线程浅析[线程分离] 线程的初始化和销毁 什么是线程的分离 线程分离函数 线程的初始化和销毁回想一下线程的创建pthread_create的时候,第二个参数是pthread_attr_t,那么这个参数类型代表的是什么??attr是特征...
  • 浅析Linux线程调度

    万次阅读 2014-12-20 13:47:22
    Linux中,线程是由进程来实现,线程就是轻量级进程( lightweight process ),因此在Linux中,线程的调度是按照进程的调度方式来进行调度的,也就是说线程是调度单元。Linux这样实现的线程的好处的之一是:...
  • 线程间使用有名管道通信 创建有名管道,如果管道存在则直接使用 //创建有名管道,如果管道存在则直接使用 int n = mkfifo(&quot;./myfifo&quot;,0664); if( n &amp;lt; 0 &amp;amp;&amp...
  • Linux 线程管理

    千次阅读 2016-11-30 16:11:34
    相信大家用java语言写线程已经很熟悉了,今天我们就来看下,在Linux下开发的时候怎么进行线程的管理 1 pthread_create函数 创建一个线程 函数原型:int pthread_create((pthread_t thread, pthread_attr_t *...
  • Linux线程浅析[线程的同步和互斥之线程信号量] 什么是线程信号量 线程信号量的相关函数 使用信号量来进行互斥和同步的问题 4. 什么是线程信号量 在之前有一篇博客讲了进程的信号量,singal函数,这个函数...
  • Unix / Linux 线程的实质

    千次阅读 2019-12-12 16:32:17
    Unix / Linux 线程的实质 线程与进程的比较 概述: 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 91,181
精华内容 36,472
关键字:

linux线程阻塞等待

linux 订阅