精华内容
下载资源
问答
  • for(int i=10;i>0;i--) pthread_create(&pid,NULL,doit,NULL); 怎么创建出来的线程ID是重复的啊?应该怎么处理快速创建线程的时候,线程ID会复用?
  • python 创建多个线程并启动

    千次阅读 2017-11-09 11:16:47
    创建多个线程并启动这些线程 th_num : 15 th_num = conf["crawl_threads"] self._thread_list = [] self._thread_states = [None,] * th_num for tid in range(th_num): th = threading.Thread(target=self.cr


    创建多个线程并启动这些线程          th_num : 15

    th_num = conf["crawl_threads"]
    self._thread_list = []
    
    self._thread_states = [None,] * th_num
    for tid in range(th_num):
        th = threading.Thread(target=self.crawl_process, args=(tid,) )
        self._thread_list.append(th)
        th.start()


    判断此线程是否存在,若不存在 则新建并启动线程

    if self._thread_handle != None:
        raise ValueError, "Loader has already started"
    self._thread_handle = threading.Thread(target=self._loop_scan, args=())
    
    self._scan_flag = True
    self._thread_handle.start()

    展开全文
  • 【Linux】利用fork()创建多个线程

    千次阅读 2016-12-19 17:35:37
    由于fork()结构的特殊性,如果要用fork()创建多个线程,并不像pthread_create()那样轻松,而且最关键的一点,是你利用for循环和fork()创建出来的多线程,会不明不白地多出N条线程。这主要是由于对fo

    在《【Linux】fork()》(点击打开链接)只是简单交代了如同利用fork()创建子线程的方法,实际是更应该说将一个程序一分为二的方法。还有很多事情隐藏在其中值得细致思考。由于fork()结构的特殊性,如果要用fork()创建多个线程,并不像pthread_create()那样轻松,而且最关键的一点,是你利用for循环和fork()创建出来的多线程,会不明不白地多出N条线程。这主要是由于对fork()的理解不够所造成的。比如如下代码:

    #include <stdio.h>
    int main(){ 
    	pid_t pid[2]; 
    	int i;
    	for(i=0;i<2;i++){
    		if((pid[i]=fork())<0){ 
    			printf("Fork() Error!"); 
    		} 
    		else if(pid[i]==0){
    			printf("This is parent %d,child is %d\n",getppid(),getpid());
    		}
    		else{
    			wait(5); 
    		}
    	}
    	return 0; 
    }

    看起来好像没有任何问题,创建2条子线程,就是在原有fork()的基础上,建立一个for而已。

    但就是不知道会创建出4条线程。那是因为,问题没有想象中的那样简单,父进程现在标号为i=1的循环中创了一个子进程,然后第二次循环,前边的第一个子线程又创建一个子进程,这时明显系统中有四个进程。如下图所示:


    因此这种创建多个子进程的方式不可取,是否一定需要用pthread_create呢?其实并不是,可以用如下的结构,创建多个子进程,以要创建4个为例:

    #include <stdio.h>
    #define MAX_THREAD 4//设置子线程数量
    int main(){
    	int i,status,pid;
    	for(i=0;i<MAX_THREAD;i++){			
    		status=fork();
    		if (status==0||status ==-1){
    			break;
    			/*每次循环时,
    			如果发现是子进程就直接从创建子进程的循环中跳出来,
    			不让你进入循环,
    			这样就保证了每次只有父进程来做循环创建子进程的工作
    			*/
    		}
    	}	
    	if(status==-1){//一般不会这种情况!
    		printf("创建的子进程,失败");
    	}
    	else if(status==0){//每个子进程都会执行的代码
    		printf("子线程id=%d,我老爸的id=%d,i=%d\n",getpid(),getppid(),i);
    		wait(status,NULL,0);
    	}
    	else{
    		printf("父进程id=%d\n",getpid());   
    		while((pid=wait(&status))>0){ 
    			printf("终结id为%d的子线程\n", pid); 
    		}
    	}	  
    	return 0;
    }

    大家需要自己的子进程做什么,直接在else if(status==0){}这个结构里面改就行了。

    同时,注意到这里停止子进程与《【Linux】fork()》(点击打开链接)停止单个子进程是不通。父进程一般不做任何事情,相当于pthread_create里面的主函数,具体见《【Linux】线程》(点击打开链接),他唯一的职责就是让等待每一个子线程停止。

    运行结果如下图:


    大家注意到这个运行结果很有意思,i是从3到0倒着来输出的。本身程序就很有意思,if-else if-else这个结构就游离在for循环之外,却如同将这段代码做了4次。

    这是因为fork()保存现场,将线程压入栈的特性。i=0时候这个现场被创建的子线程最先入栈,所以他是最后输出的。

    if-else if-else这个结构相当于将线程栈里面的线程经过else if中的处理之后一一出栈。

    else if中最初能操作的东西,是子线程入栈时候的状态。

    大家明白了吗,其实这跟汇编语言里面的循环其实很类似的。

    展开全文
  • Java使用循环创建多个线程

    千次阅读 2019-05-19 23:31:13
    使用start()方法启动线程,则立即开始创建下一个线程。 测试代码及结果如下: 情景:循环创建一类线程,这类线程的run()方法不能立即结束,如包含循环等。 问题:创建线程后,启动线程时,使用run(...

    目录

    情景:循环创建一类线程,这类线程的run()方法不能立即结束,如包含循环等。

    问题:创建线程后,启动线程时,使用run()方法则需要等待线程的run()方法先结束,否则阻塞;使用start()方法启动线程,则立即开始创建下一个线程。

    测试代码及结果如下:


     

     情景:循环创建一类线程,这类线程的run()方法不能立即结束,如包含循环等。

    问题:创建线程后,启动线程时,使用run()方法则需要等待线程的run()方法先结束,否则阻塞;使用start()方法启动线程,则立即开始创建下一个线程。

    测试代码及结果如下:

    package thread_test;
    
    class Thread_test extends Thread{//线程类
    	@Override
    	public void run() {
    		while(true);//线程的功能函数中含有死循环
    	}
    }
    public class For_Thread {
    	public static void main(String[] args) {
    		for(int i=0;i<4;i++) {//使用循环创建线程
    			Thread_test t = new Thread_test();
    			t.start();//使用start()方法,不会阻塞
    			System.out.println(i);
    		}
    	}
    }
    

     

    package thread_test;
    
    class Thread_test extends Thread{//线程类
    	@Override
    	public void run() {
    		while(true);//线程功能函数中存在不能立即结束的循环
    	}
    }
    public class For_Thread {
    	public static void main(String[] args) {
    		for(int i=0;i<4;i++) {//循环创建线程
    			Thread_test t = new Thread_test();
    			t.run();//使用run()方法会阻塞
    			System.out.println(i);
    		}
    	}
    }

    当线程的run()函数可以立即结束时,启动线程时,使用run()方法可以立即结束

    展开全文
  • 转载: http://www.cnblogs.com/love-DanDan/p/8724245.html这里说一下相关的基础知识: 线程概念 什么是线程 LWP:light weight process 轻量级的进程,本质仍是进程(在Linux环境下) 进程:独立地址空间,...

    转载: http://www.cnblogs.com/love-DanDan/p/8724245.html

    这里说一下相关的基础知识:

    线程概念

    什么是线程

    LWP:light weight process 轻量级的进程,本质仍是进程(在Linux环境下)

        进程:独立地址空间,拥有PCB

        线程:也有PCB,但没有独立的地址空间(共享)

        区别:在于是否共享地址空间。    独居(进程);合租(线程)。

        Linux下:    线程:最小的执行单位

                     进程:最小分配资源单位,可看成是只有一个线程的进程。

    Linux内核线程实现原理

    类Unix系统中,早期是没有"线程"概念的,80年代才引入,借助进程机制实现出了线程的概念。因此在这类系统中,进程和线程关系密切。

    1. 轻量级进程(light-weight process),也有PCB,创建线程使用的底层函数和进程一样,都是clone

    2. 从内核里看进程和线程是一样的,都有各自不同的PCB,但是PCB中指向内存资源的三级页表是相同的

    3. 进程可以蜕变成线程

    4. 线程可看做寄存器和栈的集合

    5. 在linux下,线程最是小的执行单位;进程是最小的分配资源单位

    察看LWP号:ps –Lf pid 查看指定线程的lwp号。

    三级映射:进程PCB --> 页目录(可看成数组,首地址位于PCB中) --> 页表 --> 物理页面 --> 内存单元

    参考:《Linux内核源代码情景分析》 ----毛德操

    对于进程来说,相同的地址(同一个虚拟地址)在不同的进程中,反复使用而不冲突。原因是他们虽虚拟址一样,但,页目录、页表、物理页面各不相同。相同的虚拟址,映射到不同的物理页面内存单元,最终访问不同的物理页面。

    但!线程不同!两个线程具有各自独立的PCB,但共享同一个页目录,也就共享同一个页表和物理页面。所以两个PCB共享一个地址空间。

        实际上,无论是创建进程的fork,还是创建线程的pthread_create,底层实现都是调用同一个内核函数clone。

        如果复制对方的地址空间,那么就产出一个"进程";如果共享对方的地址空间,就产生一个"线程"。

        因此:Linux内核是不区分进程和线程的。只在用户层面上进行区分。所以,线程所有操作函数 pthread_* 是库函数,而非系统调用。

    线程共享资源

        1.文件描述符表

        2.每种信号的处理方式

        3.当前工作目录

        4.用户ID和组ID

        5.内存地址空间 (.text/.data/.bss/heap/共享库)

    线程非共享资源

        1.线程id

        2.处理器现场和栈指针(内核栈)

        3.独立的栈空间(用户空间栈)

        4.errno变量

        5.信号屏蔽字

        6.调度优先级

    线程优、缺点

        优点:    1. 提高程序并发性    2. 开销小    3. 数据通信、共享数据方便

        缺点:    1. 库函数,不稳定    2. 调试、编写困难、gdb不支持    3. 对信号支持不好

        优点相对突出,缺点均不是硬伤。Linux下由于实现方法导致进程、线

    程差别不是很大。

    线程控制原语

    pthread_self函数

    获取线程ID。其作用对应进程中 getpid() 函数。

        头文件:#include <pthread.h>

        pthread_t pthread_self(void);    返回值:成功:0;    失败:无!

    pthread_t:当前Linux中可理解为:typedef unsigned long int pthread_t;//无符号长整形

        线程ID:pthread_t类型,本质:在Linux下为无符号整数(%lu),其他系统中可能是结构体实现

        线程ID是进程内部,识别标志。(两个进程间,线程ID允许相同)

        注意:不应使用全局变量 pthread_t tid,在子线程中通过pthread_create传出参数来获取线程ID,而应使用pthread_self。

    pthread_create函数

    创建一个新线程。        其作用,对应进程中fork() 函数。

        头文件:#include <pthread.h>

        int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

        返回值:成功:0;    失败:错误号    -----Linux环境下,所有线程特点,失败均直接返回错误号。

    参数:    

        pthread_t:当前Linux中可理解为:typedef unsigned long int pthread_t;//无符号长整形

    参数1:传出参数,保存系统为我们分配好的线程ID

        参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。

        参数3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。参数是函数指针,只能传递函数名,不能传递参数。所以就是只能有一个参数。

        参数4:线程主函数执行期间所使用的参数。

    在一个线程中调用pthread_create()创建新的线程后,当前线程从pthread_create()返回继续往下执行,而新的线程所执行的代码由我们传给pthread_create的函数指针start_routine决定。start_routine函数接收一个参数是通过pthread_create的arg参数传递给它的,该参数的类型为void *,这个指针按什么类型解释由调用者自己定义。start_routine的返回值类型也是void *,这个指针的含义同样由调用者自己定义。start_routine返回时,这个线程就退出了,其它线程可以调用pthread_join得到start_routine的返回值,类似于父进程调用wait(2)得到子进程的退出状态,稍后详细介绍pthread_join。

    pthread_create成功返回后,新创建的线程的id被填写到thread参数所指向的内存单元。我们知道进程id的类型是pid_t,每个进程的id在整个系统中是唯一的,调用getpid(2)可以获得当前进程的id,是一个正整数值。线程id的类型是thread_t,它只在当前进程中保证是唯一的,在不同的系统中thread_t这个类型有不同的实现,它可能是一个整数值,也可能是一个结构体,也可能是一个地址,所以不能简单地当成整数用printf打印,调用pthread_self(3)可以获得当前线程的id。

    attr参数表示线程属性,本节不深入讨论线程属性,所有代码例子都传NULL给attr参数,表示线程属性取缺省值,感兴趣的读者可以参考APUE。

    现在我们先预热:创建一个新线程,打印线程ID。注意:链接线程库 -lpthread

    #include <stdio.h>

    #include <pthread.h>

    #include <unistd.h>

    void *tfn(void *arg)

    {

        printf("我是线程,我的ID = %lu\n", pthread_self());

        return NULL;

    }

    int main(void)

    {

        pthread_t tid;

        pthread_create(&tid, NULL, tfn, NULL);

        sleep(1);

        printf("我是进程,我的进程ID = %d\n", getpid());

        return 0;

    }

    结果:

    由于pthread_create的错误码不保存在errno中,因此不能直接用perror(3)打印错误信息,可以先用strerror(3)把错误码转换成错误信息再打印。如果任意一个线程调用了exit或_exit,则整个进程的所有线程都终止,由于从main函数return也相当于调用exit,为了防止新创建的线程还没有得到执行就终止,我们在main函数return之前延时1秒,这只是一种权宜之计,即使主线程等待1秒,内核也不一定会调度新创建的线程执行,下一节我们会看到更好的办法。要这样写命令:gcc -pthread pthread_create.c -o pthread_create

    现在进入主题:循环创建多个线程,每个线程打印自己是第几个被创建的线程。(类似于进程循环创建子进程)

    #include <pthread.h>

    #include <stdio.h>

    #include <unistd.h>

    #include <stdlib.h>

    void *tfn(void *arg)

    {

        int i;

        i = (int)arg;

        sleep(i); //通过i来区别每个线程

        printf("我是第%d个线程,我的线程ID = %lu\n", i + 1, pthread_self());

        return NULL;

    }

    int main(int argc, char *argv[])

    {

        int n = 5, i;

        pthread_t tid;

        if (argc == 2)

            n = atoi(argv[1]);

        for (i = 0; i < n; i++) {

            pthread_create(&tid, NULL, tfn, (void *)i);

            //将i转换为指针,在tfn中再强转回整形。

        }

        sleep(n);

        printf("我是main函数,但是我不是进程,我的ID = %lu\n", pthread_self());

        return 0;

    }

    结果:

    一切正常,现在我解释一些代码:  pthread_create(&tid, NULL, tfn, (void *)i);这里的 (void *)i参数应该是指针,但是我们这里是将其强转为void*类型了,并且编译过程中也给我警告了:

    那么,为何一切正常,是编译器为我们做了不知名的优化?或者是巧合?实际上,这是因为的我的机器是64位机,如果是在32位机上编译是没有这样的错误的。这个警告是在说intvoid转化中的长度不一致(在我的机器上)。void64位机上是8位,int一般来说都是4位。这在第一次转化的时候是小变大,会发生补零,在高位上补零;第二次在i = (int)arg;这里发生大变小转化,会截取,截取高位。所以,实际上对于这个程序来说是没有影响的。所以那两个警告是没有问题的。其他的我相信是没有什么问题的。

    拓展思考:将pthread_create函数参4修改为(void *)&i, 将线程主函数(tfn)内改为 i=*((int *)arg) 是否可以?

    即变成这样: pthread_create(&tid, NULL, tfn, (void *)&i);i=*((int *)arg) ;行不行试试再说:结果也看到了,虽然没有警告了,但是结果却不对了。它不从1开始了,一会儿4个线程,一会儿5个线程。这很蛋疼啊:第四个参数应该是指针啊,没错啊。可就是不对。其实也很好理解的,线程之间共享一个用户空间,我们这样传递的是i的地址过去,然后在运行线程主函数的时候依据地址找i的值,那么,问题出现了,cpu是个很快的男人,从main到线程主函数这之间有时间差吧?所以,在那么点时间内,i的值发生改变了。那为什么有时候线程个数不足?上面只要main一结束,管你后面是不是还有线程的,统统杀死。

    展开全文
  • 问题:就是CPUpthread_create创建多个线程,执行GPU代码,会不会有问题?[size=18.9999980926514px]答:没有任何问题的。你的这个模型(开多个CPU线程,每个线程单独处理1个stream上的kernel启动或者复制任务)其实...
  • 多线程(一):创建线程线程的常用方法

    万次阅读 多人点赞 2018-09-01 19:14:23
    了解并发编程:实际工作中很少写多线程的代码,这部分代码一般都被人封装起来了,在业务中使用多线程的机会也不是很(看具体项目),但是作为一高级程序员如果不会多线程是说不过去的。 二:进程与线程 ...
  • 主要介绍怎么用C#动态创建若干个线程,并且执行他们。
  • Thread提供了一个让一个线程等待另一个线程执行完的方法——join();当线程A调用B线程join()方法后,线程A将会阻塞,只有等B线程执行完后在会执行线程A public class ThreadMain { public static void main...
  • 多线程——创建线程

    千次阅读 2015-01-17 21:29:43
    一个操作系统可以运行多个进程,一个进程内可以运行多个线程。每个应用程序至少运行在一个线程上。当只有一个线程时,称作单线程应用程序,该线程由系统自动创建。   下面看一个简单单线程例子: ...
  • 多个线程同步执行ping ip示例

    千次阅读 2017-01-13 11:41:51
    多个线程同步执行ping ip
  • 易语言大漠多线程创建线程

    千次阅读 2020-05-30 09:22:19
    进程(process)和线程(thread)是操作系统的基本概念 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一...同一个进程中的多个线程之间可以并发执行 第一课易语言大
  • C语言创建多线程

    万次阅读 2017-12-03 22:47:57
    线程是计算机中独立运行的最小... Linux操作系统在一个进程内生成多个线程。多线程和多进程相比,拥有以下优点: (1)进程都有独立的地址空间,创建新进程要耗费时间为期分配系统资源,而线程共享进程的地址空间
  • ring.c: 创建N个线程,它们构成一个环 • 创建N个线程:T1、T2、T3、… TN • T1向T2发送整数1 • T2收到后将整数加1 • T2向T3发送整数2 • T3收到后将整数加1 • T3向T4发送整数3 • … • TN收到后将整数加1 ...
  • 万字图解Java多线程

    万次阅读 多人点赞 2020-09-06 14:45:07
    java多线程我个人觉得是javaSe中最难的一部分,我以前也是感觉学会了,但是真正有多线程的需求却不知道怎么下手,实际上还是对多线程这块知识了解不深刻,不知道多线程api的应用场景,不知道多线程的运行流程等等,...
  • 进程(process)和线程(thread)是操作系统的基本概念 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的...同一个进程中的多个线程之间可以并发执行进程和线程的区别在
  • Java多线程之如何创建多线程

    千次阅读 2018-05-24 13:41:34
    Java与多线程的关系我们平时写的好多简单程序就有多个线程参与,你可能会感到惊讶,但是事实就是这样。Java程序从main()方法开始执行,然后按照既定的代码逻辑执行,看似没有其他线程参与,但实际上Java程序天生就是...
  • 多个线程调用同一个线程函数

    千次阅读 2012-03-08 20:15:53
    多个线程调用同一个线程函数 悬赏分:50 - 解决时间:2007-12-11 13:59 如题,能这样吗?因为有很多个操作,但是这些操作都是一样的,所以想用相同的线程函数,但是感觉运行时线程还是一个一个运行,并没有...
  • 【java并发】多个线程间共享数据

    万次阅读 多人点赞 2016-05-31 22:56:36
    先看一个多线程间共享数据的问题: ...我们先把上面这个问题放在一边,慢慢分析多个线程之间共享数据的一些情况,从最简单开始,分类分析完了后,到时候也好解决上面这个问题了。 1. 每个线程执行的任务相同  这
  • python多进程多线程,多个程序同时运行

    千次阅读 多人点赞 2021-04-08 13:47:15
    python 多线程 多进程同时运行 多任务要求 python 基础语法 python 文件目录操作 python 模块应用 开发工具 pycharm ...在一段时间内交替执行多个任务, 例如单核cpu 处理多任务, 操作系统让各个任务交
  • 两种创建多线程方式

    千次阅读 2020-11-20 11:37:38
    一个进程可以有一个线程、也可以有多个线程 单线程:安全性高,效率低。 多线程:安全性低,效率高。 方式1:继承Thread 方式1:继承Thread。重写run方法,创建线程对象,调用static开启线程 子类继承...
  • # 开多个线程 是否跟CPU有关? 我本机开60个线程看起来没有起多大作用,这是怎么回事 求大神解答
  • C++ 多线程创建多线程CreateThread

    万次阅读 2016-08-25 17:18:10
    一、为什么要写这篇博客一直对C++多线程一知半解,感觉没有实际进入过C++多线程的世界,因此想从头开始慢慢真正进入C++多线程,真正了解多线程。因为我也想了解Linux下的C++ 编程,因此我也会在Linux平台下进行编写...
  • 多线程~~简单的线程创建,C语言实现

    万次阅读 多人点赞 2015-04-24 21:30:58
    通过主线程,可以创建多个线程或进程。  使用多线程,可以提高程序的执行效率。  线程创建函数CreateThread(),属于API函数;  函数原型为: HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttr
  • Java 多线程:彻底搞懂线程池

    万次阅读 多人点赞 2019-07-09 19:27:00
    熟悉Java多线程编程的同学都知道,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了。 目录 1 线程池的优势 2 线程池的使用 3 线程池的工作原理 4 线程池的参数 4.1 任务队列...
  • springboot 开启多个线程

    万次阅读 2018-03-30 16:59:33
    spring默认的线程是有限的(反正默认的不太好之类的),需要自己手工配置线程池效果会更好。@Configuration @EnableAsync//开启对异步任务的支持 public class ThreadAsyncConfigurer implements AsyncCon...
  • 2、await发生在多个子线程,主线程负责countDown,相当于管理多个线程的同步时机。 package multithread; import java.util.HashMap; import java.util.Iterator; import java.util.concurrent.CountDown
  • JAVA多线程实现多个线程同时运行

    千次阅读 2019-09-18 05:32:44
    * 多个线同时运行 * CyclicBarrier */ public class CyclicBarrierDemo { private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5); public static void main(String[] args) { ExecutorService ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,380,110
精华内容 552,044
关键字:

创建多个线程