首页
学习
活动
专区
圈层
工具
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

linux子线程如何不阻塞主线程

在Linux系统中,子线程不阻塞主线程通常涉及到多线程编程的概念。在多线程编程中,主线程(也称为父线程)和子线程可以并发执行,这意味着它们可以同时运行,互不干扰。为了实现这一点,需要使用特定的编程技术来确保子线程的执行不会影响主线程的运行。

基础概念

  • 线程(Thread):线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
  • 主线程(Main Thread):程序启动时创建的第一个线程,通常是程序执行的入口点。
  • 子线程(Child Thread):由主线程创建的其他线程。

相关优势

  • 并发执行:子线程可以在后台执行耗时任务,而主线程可以继续响应用户输入或其他事件。
  • 资源共享:线程之间可以共享内存空间,这使得数据交换更加高效。
  • 提高性能:合理使用多线程可以提高程序的执行效率,特别是在I/O密集型或计算密集型任务中。

类型

  • 用户级线程:完全在用户空间实现,操作系统内核对它们不可见。
  • 内核级线程:操作系统内核直接管理的线程,它们有自己的内核栈和寄存器集。

应用场景

  • 服务器程序:如Web服务器可以同时处理多个客户端请求。
  • 图形界面程序:主线程负责更新UI,子线程负责执行耗时任务,如文件读写、网络通信等。
  • 数据处理:如大数据分析、科学计算等,可以利用多线程加速处理速度。

遇到的问题及解决方法

问题:子线程阻塞主线程

这通常发生在子线程执行耗时操作时,如果没有正确地管理线程间的同步和通信,可能会导致主线程等待子线程完成。

原因

  • 同步问题:子线程在执行某些操作时可能需要等待其他资源,如果这些操作没有正确同步,可能会导致主线程阻塞。
  • 死锁:当两个或多个线程互相等待对方释放资源时,可能会发生死锁,导致所有涉及的线程都无法继续执行。

解决方法

  • 使用线程同步机制:如互斥锁(mutex)、信号量(semaphore)、条件变量(condition variable)等,确保线程间的操作是同步的。
  • 异步编程:使用异步I/O或事件驱动模型,如Linux的epollselectpoll等,可以让主线程在等待I/O操作完成时继续执行其他任务。
  • 线程池:预先创建一组线程,当有任务需要执行时,从线程池中取出一个线程来执行任务,这样可以减少线程创建和销毁的开销。

示例代码

以下是一个简单的C语言示例,展示如何在Linux中使用POSIX线程(pthread)创建子线程,并确保主线程不会被阻塞:

代码语言:txt
复制
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

void* thread_function(void* arg) {
    int i;
    for (i = 0; i < 5; i++) {
        printf("子线程执行中: %d\n", i);
        sleep(1); // 模拟耗时操作
    }
    return NULL;
}

int main() {
    pthread_t thread_id;
    int res;

    // 创建子线程
    res = pthread_create(&thread_id, NULL, thread_function, NULL);
    if (res != 0) {
        perror("线程创建失败");
        exit(EXIT_FAILURE);
    }

    // 主线程继续执行其他任务
    for (int i = 0; i < 5; i++) {
        printf("主线程执行中: %d\n", i);
        sleep(1);
    }

    // 等待子线程结束
    pthread_join(thread_id, NULL);

    printf("主线程结束\n");
    return 0;
}

在这个示例中,pthread_create函数用于创建子线程,pthread_join函数用于等待子线程结束。主线程和子线程可以并发执行,互不阻塞。

参考链接

请注意,多线程编程涉及到复杂的同步和通信问题,实际应用中需要仔细设计和测试以确保程序的正确性和稳定性。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

linux~~监控子进程&创建新的线程

1.wait函数介绍 wststus参数,输出类型的参数,进程的状态改变的原因的相关信息,如果我们不关心这个子进程为什么状态发生了改变,我们就可以把这个参数设置为nullptr; 终止的子进程的pid号码作为这个...wait函数的返回值; wait等待任意的一个子进程终止退出,如果子进程都不结束,wait将会一直处于一个阻塞的状态,有一个子进程终止,这个函数就会有对应的终止进程的返回值; 所有子进程全部终止结束,这个时候的...,我们可以称之为父进程,这个父进程创建了三个子进程,分别给这三个子进程创建休眠的时间,5s,10s,15s等等; 这个时候的main函数里面设置了相关的参数,其中这个里面的第一个参数就是argc,这个参数的意义就是我们的...,1,2,3分别表示的就是3个子进程,因此我们的这个for循环是从这个1开始循环的,当返回值是-1的时候,就说明这三个子进程全部结束了; 其中这个里面的while循环会一直进行,返回值-1这个子进程全部结束.../a.out就是我们编译之后生成的可执行程序,10,5,15就是子进程的休眠时间,这个就是对应的我们的这个main函数里面的参数; 3.pthread_create函数介绍 3.1总体介绍 这个函数就是线程的创建函数

3900

Linux:多线程(二.理解pthread_t、线程互斥与同步、基于阻塞队列的生产消费模型)

1.理解Linux下线程——理解tid 我们知道Linux系统中没有线程的概念,只有轻量级进程。...而LWP则是内核管理轻量级进程的抽象,用于在内核空间进行线程的调度和管理。 在Linux系统中,线程库(如pthread库)会将pthread_t映射到对应的LWP上,以便内核进行线程的调度。...Linux上提供的这把锁叫互斥量 2.3Linux中互斥量/互斥锁(mutex) 大部分情况,线程使用的数据都是局部变量,变量的地址空间在线程栈空间内,这种情况,变量归属单个线程,其他线程无法获得这种变量...一个函数在重入的情况下,运行结果不会出现任何不同或者任何问题,则该函数被称为可重入函数,否则,是不可重入函数 线程安全是针对线程执行时,各个线程的相互关系。...在多线程编程中,这通常是一个数据结构(如队列、缓冲区等),用于临时存储数据,供生产者和消费者线程进行访问。 一般我们使用阻塞队列作为缓冲区 功能:作为生产者和消费者之间数据传递的桥梁。

75110
  • 【Linux】互斥锁、基于阻塞队列、环形队列的生产消费模型、单例线程池

    Linux上提供的这把锁叫互斥量。 | 线程或进程什么时候被切换?...如果申请锁的时候,锁已经被别的线程拿走了怎么办?其他线程阻塞等待。 线程在访问临界区的时候,可不可以被切换?可以,我被切走,其他线程也不能进来,因为我走的时候是带着锁走的,保证了原子性。...还有如果阻塞等待的线程和其他线程所发的信号数量不匹配,也就是出现了伪唤醒,也会出现问题。...为了规避这种问题,这里判断阻塞队列是否为满我们就不同if判断了,而是改用while判断,只要阻塞队列为空,就一直阻塞等待,这样做可以规避很多可能出现的错误。...一个函数在重入的情况下,运行结果不会出现任何不同或者任何问题,则该函数被称为可重入函数,否则,是不可重入函数。

    3700

    【Linux】生产者消费者模型:基于阻塞队列和环形队列 | 单例模式线程池

    当线程申请所成功,才能向后执行,否则阻塞等待,该进程访问完成后,释放锁,然后其它线程再来申请锁。...为了解决这个问题,我们可以让所有阻塞的线程排成一个队,当一个线程释放锁后,就排到队尾,然后由位于队首的线程申请锁,这样就很好地避免了线程的饥饿问题。...让所有阻塞等待的线程都到条件变量队列下等待,当一个线程释放锁时,就唤醒一个条件变量队列中的线程。...悲观锁:在每次取数据时,总是担心数据会被其他线程修改,所以会在取数据前先加锁(读锁,写锁,行锁等),当其他线程想要访问数据时,被阻塞挂起。...linux中也有一批关于自旋锁的接口:  用法都和互斥锁的类似。

    35010

    AQS这样学就很简单了

    哈喽,我是子牙。十余年技术生涯,一路披荆斩棘从技术小白到技术总监到JVM专家到创业。技术栈如汇编、C语言、C++、Windows内核、Linux内核。特别喜欢研究虚拟机底层实现,对JVM有深入研究。...显然,让线程运行结束不合适,因为线程该执行的任务还未执行。正确的做法肯定是先把这个线程保存下来,然后让线程阻塞。待持有锁的线程运行结束再唤醒执行。...阻塞 线程如果没有抢到锁依然在那尝试抢锁这就是所谓的自旋锁,很显然,这样很浪费资源,肯定没有抢到锁的线程执行完任务唤醒高效。那如何不占用资源呢?就是阻塞自己,让出资源,不被调度。...唤醒 未抢到锁的线程为了不占用资源阻塞了自己,拿到锁的线程执行完任务需要来唤醒,不然就会出现奇怪的现象:抢到锁的线程执行完任务退出了,未抢到锁的线程全部阻塞在那里等待唤醒。...题外话 子牙手写JVM小班四期招生即将结束。

    44290

    Golang 基础:原生并发 goroutine channel 和 select 常见使用场景

    : 线程退出时要考虑新创建的线程是否要与主线程分离(detach) 还是需要主线程等待子线程终止(join)并获取其终止状态?...优势: 占用内存小,goroutine 初始栈只有 2k,比 Linux 线程小多了 用户态调度,不需要内核介入,代价更小 一退出就会被回收 提供 channel 通信 无论是 Go 自身运行时代码还是用户层...阻塞等待 fmt.Println("worker finished") } 上面的代码中,主 routine 创建了一个函数,然后在子 routine 中执行,主 routine...中读取等待这个 channelA 主 routine 关闭 channel,然后阻塞在 channelB 上,此时所有子 routine 开始执行 所有子 routine 执行完后,通过 channelB...routine 通知所有子 routine 开始】 和【子 routine 通知主 routine 任务结束】。

    1.1K30

    反制面试官 | 14张原理图 | 再也不怕被问 volatile!

    ,然后对变量进行操作,操作完成后再将变量写会主内存,不能直接操作主内存中的变量,各个线程中的工作内存中存储着主内存中的变量副本拷贝,因此不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成...,名字叫做子线程 子线程先休眠3s,然后设置number=100。...它们既可以保证可见性,又可以保证原子性为何不用呢?...因为synchorized和lock是排他锁(悲观锁),如果有多个线程需要访问这个变量,将会发生竞争,只有一个线程可以访问这个变量,其他线程被阻塞了,会影响程序的性能。...volatile 保证了单线程下指令不重排:通过插入内存屏障保证指令执行顺序。 volatitle不保证原子性,如a++这种自增操作是有并发风险的,比如扣减库存、发放优惠券的场景。

    35121

    nginx,memcached,redis网络模型总结

    这种进程模型的好处: 每个worker进程相互独立,无需加锁,省掉锁的开销 多个worker进程互相不影响,提高稳定性 多进程提供性能 nginx利用多进程+非阻塞的模型,能轻松处理上万连接。...t.handler = write_handler; } run_tasks_add(t); } 惊群现象 master进程会事先创建好监听套接字,然后fork worker子进程时...nginx进程间通信 nginx的进程通信分为三种类别:linux 系统与nginx 通信, master 进程与worker进程通信, worker进程间通信。...linux 系统与nginx之间通信,通过信号进行,通过信号控制nginx重启、关闭以及加载配置文件等。...Redis事件模型 Redis采用单线程模型,通过IO多路复用来监听多个连接,非阻塞IO,同时单线程避免了不必要的锁的开销。

    1.8K20

    30道最常问的Java基础面试题

    什么是Java程序的主类?应用程序和小程序的主类有何不同?**一个程序中可以有多个类,但只能有一个类是主类。在Java应用程序中,这个主类是指包含main()方法的类。...而在Java小程序中,这个主类是一个继承自系统类JApplet或Applet的子类。应用程序的主类不一定要求是public类,但小程序的主类要求必须是public类。主类是Java程序执行的入口点。...**阻塞(block)**:阻塞状态是指线程因为某种原因放弃了cpu使用权,也即让出了cpu timeslice,暂时停止运行。...同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁 被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。 (三)....其他阻塞: 运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。

    30910

    11 Python 进程与线程编程

    2.1 创建 我们创建了两个函数,并将两个都放在主函数里面执行,我们来看看执行的结果。...从执行结果来看我们work_a 已经执行在另外一个进程中了,work_b 和 主函数 的 函数id 是一样的, 说明它们实在同一个进程中的。...2.2 阻塞 如果我们想要让两个 子进程先执行完毕再执行主进程这个就可以使用到join。 我们来优化一下代码。 再来看看执行效果。...从执行结果来看,我们确实是实现了先执行完子线程再执行主线程,至于为什么控制台看起来优点乱,是因为有的进程它执行的时间是一致的。重叠在一起了。...确实如此,异步和多进程和多线程它们类似于兄弟,让我们看看它们之间有何相同有何不同。 首先我们要知道,异步实际上也是一种线程。

    43410

    线程的概念及linux下线程库相关函数的使用

    3.对信号支持不好 4.linux线程库中相关函数的使用。...指向创建线程所执行函数的入口地址,函数执行完毕,则线程结束。 参数4:线程主函数执行期间所使用的参数。...添加单线程退出函数的执行结果: 可见,单线程退出函数确实起到了作用。 4.4阻塞等待线程退出,回收线程的资源。...调用该函数的线程将挂起等待,为阻塞的状态。直到id为thread的线程终止。...获取子线程的退出状态并输出。 以上即线程的相关概念以及Linux系统下线程库相关重要的函数具体应用,大家也可以自行举例,验证函数。进一步的去理解线程的真正意义以及如何使用线程相关的开发。

    56930

    muduo源码分析

    主Reactor只有一个,只负责监听新的连接,accept后将这个连接分配到子Reactor上。子Reactor可以有多个。这样可以分摊一个Eventloop的压力,性能方面可能会更好。...如果没有设置子Reactor,则是默认的单线程模型,新的连接会再由主Reactor进行管理。...但其实这里似乎有些不合适的地方:多个TcpServer之间可以共享同一个主EventLoop,但是子Eventloop线程池却不能共享,这个是每个TcpServer独有的。...不过netty的主EventLoop和子Eventloop池都是可以共享的。 业务线程池 对于一些阻塞型或者耗时型的任务,例如MySQL操作等。...对于这类耗时型的任务,一般做法是可以放在另外单独线程池中运行,这样就不会阻塞IO线程的运行了。我们一般把这种处理耗时任务的线程叫做Worker线程。

    2.2K51

    这也许是22年国内最牛的Java面试八股文合集(全彩版),不接受反驳

    、spring、springboot、springcloud、dubbo、mybatis、redis、网络IO、Linux、MQ、zookeeper、netty、大数据、算法、项目、设计模式等等;刷完这一套高质量题集...说说阻塞队列的实现:可以参考ArrayBlockingQueue的底层实现(锁和同步都行)进程通讯的方式:消息队列,共享内存,信号量,socket通讯等为什么要用线程池线程池的基础概念自带线程池的各种坑...volatile关键字的用法:使多线程中的变量可见线程的几种状态常用的线程池模式以及不同线程池的使用场景线程间通信,wait和notifywait和notify的理解与使用java线程池主线程等待子线程执行完成进程和线程的区别什么叫线程安全...举例说明并发、同步的接口或方法HashMap是否线程安全,为何不安全。...JAVA阻塞队列原理......SpringSpring 原理Spring 特点Spring核心组件Spring 常用模块Spring主要包Spring 常用注解Spring 第三方结合Spring IOC

    2.6K60

    后台开发:核心技术与应用实践--线程与进程间通信

    条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补互斥锁的不足,它常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。...,如果有另外的线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁的请求,这样可以避免读模式锁长期占用,而等待的写模式锁请求则长期阻塞。...Linux 系统下使用 fork() 函数创建一个子进程,其函数原型如下: #include pid_t fork(void); fork()函数不需要参数,返回值是一个进程标识符...是 Linux shell 中的一个内置变量,其中保存的是最近一次运行的进程的返回值。 在 UNIX/Linux 中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。...;如果没有找到这样一个子进程, wait 就会一直阻塞在这里,直到有一个出现为止。

    1.4K30

    Java并行流陷阱:为什么指定线程池可能是个坏主意

    任务为递归型任务,任务可以划分为子任务,空闲线程可以”窃取“待执行任务,充分利用线程池。一般情况下,使用公用池时,任务队列中会存在比较多的小任务。...其底层逻辑可以总结为:当 ForkJoin 任务执行时,其可以获得线程池上下文,任务(子任务)会在线程池中执行。但是,这个 trick 是不可靠的。...慎用并行流首先,无论如何不要在并行流里执行阻塞任务,除非你对于其内部实现非常了解,否则,你会遇到各种各样所谓的坑。...使用方便切分的数据结构,如ArrayList、HashMap、数组、range 等。你需要理解 Spliterator 的底层实现。...我们可以在最初阶段估算并行度,比如并行排序,一方面只有可以并行的运算才可以提高性能;另一方面,任务划分可能会划分过多的子任务,结果收集难以并行运算,还有线程上下文切换、数据同步等开销。

    13810

    Java | 如何停止一个线程

    ,并阐述无误 目录 如何停止一个线程【概述】 为何不能简单地停止一个线程?...; 需要设计一个方案, 可以在逻辑上, 随时中断被取消的任务线程; 因为物理上没办法简单停止掉了; 但是我们可以结束掉线程中的任务; 为何不能简单地停止一个线程?...,申请内存锁, 这时候内存锁被线程1持有了, 线程3只能阻塞,等待线程1释放内存锁; ?...接着, 我们暂停线程1,这时候线程1虽然暂停了, 但是它仍然它仍然持有内存锁; 线程3还是阻塞,得等; 万一这时候线程3还有线程1的锁, 那都死锁了; 所以就存在很多问题, 于是线程的暂停和继续的...这里右侧的调用方, 让主线程休眠2秒, 是为了确保启动的子线程thread有机会执行一段时间; 【关于就绪转运行需要时间片的问题】 记得我们在开发的时候, 每次使用sleep()之类的方法,

    1.8K20

    来一大波后台开发项目推荐!

    阻塞、非阻塞、信号驱动 高性能 IO 两种模式:Reactor 和 Proactor( 但是 Linux 下由于缺少异步 IO 支持,基本没有 Proactor IO 复用机制:epoll、select...高性能服务器编程》 北子哥强烈推荐,这本书前半部分基本是在重复计网基础知识,但是后面几章关于高性能服务器程序框架、高性能IO、IO复用、定时器、多线程编程、线程池和进程池还是讲得非常全面到位的,值得一看...《Linux多线程服务器端编程》 同样强烈推荐,这是陈硕大佬写的书,说实话第一部分:C++ 多线程系统编程都直接把人看蒙了,没有想到 C++ 里要做到线程安全这么难,第一章看了两三遍估计才能看懂吧。。。...《Linux 多线程服务端编程》 学完网络编程就可以写点小项目练手了,这里列举几个项目: HTTP 服务器,正如前文所有,这个似乎成了 Linux C/C++ 人手一个的项目了?...更进一步可以考虑一下如何不通过服务器中转消息实现 P2P 聊天,类似 QQ,这里会涉及到 UDP 打洞、NAT 转换等知识,还是很有意思的。

    1.1K50

    GO 语言的并发模式你了解多少?

    ,例如 线程中 父线程可以通过 pthread_join 来等待子线程结束,并且还可以获取子线程的结束状态 GO 语言中等待子协程退出并且获取子协程的退出状态,咱们就可以使用通道 channel 的方式来进行处理...例子1 等待一个子协程退出,并获取退出状态 主协程中调用 help 方法得到一个 ch 通道变量,主协程阻塞着读 ch help 中开辟一个子协程去执行传入的 fn 回调函数,并传参为 ok bool...中再另起一个协程 wg.Wait() 等待所有子协程退出,并将 ch 变量写入值 主协程阻塞读取 ch 变量的值,待所有子协程都退出之后,help 中写入到 ch 中的数据,主协程就能马上收到 ch...demo: 主协程调用 help 函数,得到一个 quit chan struct{} 类型的通道变量,主协程阻塞读取 quit 的值 help 函数根据传入的参数 num 来创建 num 个子协程,...,退出的时候也是 10 个子协程退出了,主协程才退出 上述程序,如果某一个子协程出现了问题,导致子协程不能完全退出,也就是说某些子协程在 f 函数中阻塞住了,那么这个时候主协程岂不是一直无法退出???

    34220
    领券