线程的创建

线程是一种使程序在同一时间做多件事的机制,和进程一样是并发执行的。linux内核调度为每个线程分配一个时间片,使用完后等待下次调度。和进程相比,线程是一种更小的执行单位。

每个进程启动后都会有一个线程在运行,称为主线程,可以在主线程中启动多个子线程,这些线程在同一个进程中,不同线程在给定时间内执行不同的代码片段。

我们可以fork一个子进程,这个子进程就是对父进程的一个copy,包括系统分配的各种资源:虚拟内存、文件描述符等。如果在子进程关闭文件描述符,不会影响父进程对其的读写。但线程不同,每个线程都共享同一内存、文件描述符、以及其他资源。在一个线程中关闭文件描述符,其他的线程都不能读写。

在任何一个线程中调用exec,所有线程都会停止,并且当前线程所在的进程会被exec传递的程序替换。

1.线程创建

所有与线程相关的函数和数据类型都在<pthread.h>中声明,但线程函数没有被包含进C标准库中,因此,调用了线程相关API后,编译时需要添加线程库:libpthread,或者-lpthread

每个线程用一个唯一的ID表示,称为线程id,编程中类型为pthread_t.

创建一个线程很简单,只需调用以下函数即可,创建之后线程会等待系统调用随时会启动。

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

参数介绍:

thread :线程的ID,一个pthread_t类型的指针

attr: 线程的属性,一般赋值为NULL,表示使用默认值

start_routine :线程函数,在线程创建后需要执行的代码。一个普通函数,返回值、参数类型都是void*。这样可以传递任何类型的数据,只需将数据结构的指针传递,然后接收 到时强制转换。

arg :线程函数start_routine的参数

创建两个线程,分别打印“hello”和“world”,主线程打印"main"

#include <pthread.h>
#include <stdio.h>

void* thread_func(void* s)
{
        int n=10;
        while(n-- >0)
        printf("%s \n",(char*)s);
        return NULL;
}

int main()
{
        int g=10;
        pthread_t thread_id_hl;
        pthread_t thread_id_wd;
        pthread_create(&thread_id_hl,NULL,thread_func,"hello");
        pthread_create(&thread_id_wd,NULL,thread_func,"world");
        while(g-- >0)
        printf("main\n");
        return 0;

}

以上代码中创建两个线程,线程函数相同只是传递的参数不同,运行之后可以看到打印"main"个数每次都是10个,“hello”,"world"个数不够10个。只是因为main线程在两个子线程没有退出之前结束。

要等待子线程都退出之后main线程在退出,和进程中的wait相似,线程中使用pthread_join();

int pthread_join(pthread_t thread,void **retval);

参数介绍:

thread: 等待退出线程的id

retval: 线程退出时的返回值,通过指针的方式传递个*retval,如果调用pthread_join时指定的线程已经退出,*retval 会返回PTHREAD_CANCLED

一个线程的退出可以通过两种方式:1.等待线程函数执行到return返回 ;2.在线程中执行void pthread_exit(void *retval),retval为线程返回的值。无论用哪种返回方式,返回值都会在pthread_join的参数retval中获取。

如下程序,创建两个线程调用同一个函数,对线程函数传递的参数不同其返回值也不同:#include <pthread.h>

#include <stdlib.h>
#include <string.h>

#define THREAD_ONE      1
#define THREAD_TWO      2

void* thread_function(void *arg)
{
        char *retval;
        int n = *((int*)arg);
        switch(n)
        {
        case THREAD_ONE:
                retval="get from thread one.\n";
                return retval;
        case THREAD_TWO:
                retval="get from thread two.\n";
                pthread_exit((void*)retval);
        }
        return NULL;

}

int main()
{
        int thread_arg1 = THREAD_ONE;
        int thread_arg2 = THREAD_TWO;
        pthread_t thread_one;
        pthread_t thread_two;
        char *retval,*mallocaddr;

        pthread_create(&thread_one,NULL,&thread_function,(void*)&thread_arg1);
        pthread_create(&thread_two,NULL,&thread_function,(void*)&thread_arg2);

        mallocaddr = (char*)malloc(64);
        memset(mallocaddr,0,64);
        retval = mallocaddr;
        pthread_join(thread_one,(void**)&retval);
        printf("The return value. %s",retval);
        pthread_join(thread_two,(void**)&retval);
        printf("The return value. %s",retval);
        free(mallocaddr);
        return 0;
}

如以上示例,通常一个函数可能被多个线程调用,有时候函数需要知道自己被哪个进程正在运行,可以在函数中调用:pthread_t pthread_self(void)返回正在运行函数的线程id

如果在一个线程中调用pthread_join并将自己的id作为参数,函数会立刻出现错误,并返回EDEADLK。为了避免一个线程pthread_join自己的id,可以这样:

if (!pthread_equal (pthread_self (), other_thread))
	pthread_join (other_thread, NULL);

pthread_equal 函数定义:

int pthread_equal(pthread_t t1, pthread_t t2);

2.线程的joinable和detach状态

joinable状态的线程,当线程结束之后不会自动释放资源,直到其他线程调用pthread_join该线程的返回值时才会释放。

detach 状态的线程,线程结束之后会自动释放资源,其他线程不能调用pthread_join获取他的返回值。

线程这两种状态由创建时pthread_create传递的属性attr参数来控制,默认情况下为joinable状态。

将线程设置为detach状态:

pthread_attr_t attr;
pthread_t thread;
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
pthread_create (&thread, &attr, &thread_function, NULL);
pthread_attr_destroy (&attr);

在这里,多个线程创建可以使用同一个attr,使用完后要用pthread_attr_destroy删除,下次用时在phtread_attr_init

注:一个线程创建时是joinable状态,可以用pthread_detach将其转换成detach状态,反之,不可以。

线程的创建,布布扣,bubuko.com

时间: 2024-10-10 18:28:38

线程的创建的相关文章

基础学习day11--多线程一线程的创建,运行,同步和锁

1.1.进程和线程 进程:一个应用程序一般都是一个进程,正在进行的程序 每一个进程最少都有一个线程,都有一个执行顺序,该顺序是一个执行路径或者一个控制单元 线程:进程中一个独立的控制单元,线程控制着进程的执行. windows中的任务管理器,可以查看进程,linux下通过ps命令 线程是进程的最小单位 线程依赖于进程 线程随着进程的创建和创建,随着进程的结束而消亡 如迅雷:可以同时开启多个下载,就是多线程 多个程序同时执行,时CPU在很快的切换,看上去是同时执行,实际上是在CPU在切换执行. 多

Java线程的创建和基本使用

线程的创建 1.创建线程的两种方法 (1) 创建Thread的子类,并覆盖run()方法 (2) 实现Runnable接口 创建多线程的方法 方法1:通过创建Thread类的子类实现多线程,步骤如下 : 1. 定义Thread类的一个子类. 2. 定义子类中的方法run( ),覆盖父类中的 方法run( ). 3. 创建该子类的一个线程对象. 4. 通过start( )方法启动线程. 注意: 1.每个线程都将启动,每个线程都将运行直到完成. 2.一系列线程以某种顺序启动并不意味着将按该顺序执行.

C#在某个线程上创建的控件不能成为在另一个线程上创建的控件的父级

首先在form1的窗体载入中新建了一个Class1对象并将本身的引用传递进入其构造函数,然后在Class1的构造函数中创建一个线程.该线程所代理的方法事件是本类中的一个add方法.而add方法的内容则是在form1上放一个textbox.然而这个流程你需要注意的有几个问题:1.哪个是主线程?所谓主线程是第一个启动的线程,是从main开始的.form1的这个窗体是由主线程创建的.2.Thread t的线程是什么?t是由主线程创建的,t的操作内容是在由主线程创建的窗体上放一个textbox.也就是说

Java线程:创建与启动

Java线程:创建与启动 一.定义线程 1.扩展java.lang.Thread类. 此类中有个run()方法,应该注意其用法: public void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法:否则,该方法不执行任何操作并返回.   Thread 的子类应该重写该方法. 2.实现java.lang.Runnable接口. void run() 使用实现接口 Runnable 的对象创建一个线程时,启动该线程将导致在独

Java并发编程:线程的创建

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

iOS-多线程 ,整理集锦,多种线程的创建

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; //创建线程的第一种方式 NSThread *thread = [[NSThread all

java 加入一个线程、创建有响应的用户界面 。 示例代码

javajava 加入一个线程.创建有响应的用户界面 . 示例代码 来自thinking in java 4 21章  部分代码  目录21.2.11 thinking in java 4免费下载:http://download.csdn.net/detail/liangrui1988/7580155 package org.rui.thread.concurrent; /** * 加入一个线程 * 一个线程可以在其他线程之上调用join()方法,其效果是等待一段时间直到第二个线程结束才继续执行

Java再学习——线程之创建

Java创建线程有两种方法,一种是继承Thread,另一种实现Runnable或Callable接口. 一,继承Thread public class APP { public static void main(String[] args) { Thread thread = new Thread() { @Override public void run() { int i = 0; while (i < 100) { System.out.println(i++); try { Thread

【进程管理】进程(线程)创建

本节主要研究进程(线程)创建的过程,下文将不区分进程和线程: 基本知识 在linux系统中,第一个进程是系统固有的,是由内核的设计者安排好的:一个新的进程一定要由一个已存在的进程复制出来,而不是创造出来的,其实linux系统并不提供直接创建进 程的方法:创建了子进程以后,父进程可以继续走自己的路,与子进程分道扬镳,但是如果子进程先行exit(),那么将要向父进程发一个信号:父进程也可以选择睡眠,等子进程 exit()以后再去世,然后父进程再继续执行,可使用wait3()某个特定的子进程,wait