POSIX 线程编程(二)线程建立与终止

创建与终止线程


线程的管理常用的API有:

pthread_create(thread,attr,start_routine,arg)
pthread_exit(status)
pthread_cancel(thread)
pthread_attr_init(attr)
pthread_attr_destroy(attr)

创建线程:


  • 一个main程序包含一个默认的主线程,这个主线程在程序开始运行的时候由系统创建。除此之外的所有其他线程必须由程序员显式的创建。


  • pthread_create 创建一个可执行的线程。每次调用创建一个线程,同时,你可以在任何位置调用该函数。

  • pthread_create 参数:

    • thread:唯一标示一个新线程的用户不可见的标识符,由pthread_create产生

    • attr:一个线程的不可见的属性对象,可以用来设置新建线程的属性。可以传进一个线程属性对象,类型为pthread_attr_t;或者传NULL来使用默认值。

    • start_routine: 新线程创建好之后由新线程立即执行的子程序

    • arg:传给
      start_routine的一个参数。它必须为void类型的指针,当然没有参数或者使用默认可以传NULL。如果想传进多个参数,可以它们封装进一个结构体。

  • 一个进程可以创建的线程数量的最大值在不同的系统内有不同的实现。

  • 在Linux查询和设置你的系统的线程数量限制方法如下:








  • bash / ksh / sh tcsh / csh
    $ ulimit -a
    core file size (blocks, -c) 16
    data seg size (kbytes, -d) unlimited
    scheduling priority (-e) 0
    file size (blocks, -f) unlimited
    pending signals (-i) 255956
    max locked memory (kbytes, -l) 64
    max memory size (kbytes, -m) unlimited
    open files (-n) 1024
    pipe size (512 bytes, -p) 8
    POSIX message queues (bytes, -q) 819200
    real-time priority (-r) 0
    stack size (kbytes, -s) unlimited
    cpu time (seconds, -t) unlimited
    max user processes (-u) 1024
    virtual memory (kbytes, -v) unlimited
    file locks (-x) unlimited

    $ ulimit -Hu
    7168

    $ ulimit -u 7168

    $ ulimit -a
    core file size (blocks, -c) 16
    data seg size (kbytes, -d) unlimited
    scheduling priority (-e) 0
    file size (blocks, -f) unlimited
    pending signals (-i) 255956
    max locked memory (kbytes, -l) 64
    max memory size (kbytes, -m) unlimited
    open files (-n) 1024
    pipe size (512 bytes, -p) 8
    POSIX message queues (bytes, -q) 819200
    real-time priority (-r) 0
    stack size (kbytes, -s) unlimited
    cpu time (seconds, -t) unlimited
    max user processes (-u) 7168
    virtual memory (kbytes, -v) unlimited
    file locks (-x) unlimited


    % limit
    cputime unlimited
    filesize unlimited
    datasize unlimited
    stacksize unlimited
    coredumpsize 16 kbytes
    memoryuse unlimited
    vmemoryuse unlimited
    descriptors 1024
    memorylocked 64 kbytes
    maxproc 1024

    % limit maxproc unlimited

    % limit
    cputime unlimited
    filesize unlimited
    datasize unlimited
    stacksize unlimited
    coredumpsize 16 kbytes
    memoryuse unlimited
    vmemoryuse unlimited
    descriptors 1024
    memorylocked 64 kbytes
    maxproc 7168



  • 一旦建立,线程之间是并行的,同时可以在线程内创建新的线程。线程之间没有继承或者依赖关系。

线程属性


  • 默认情况下,一个线程创建之后包含一些默认属性。其中一些可以由传递进去的线程属性对象改变。

  • pthread_attr_init 和 pthread_attr_destroy 用来初始化和销毁一个线程属性对象

  • 还有一些其他API可以用来查询或者设置线程属性对象中的特定的属性。线程的属性包括:

    • 分离或可结合状态

    • 调度继承

    • 调度策略

    • 调度参数

    • 调度竞争范围

    • 栈尺寸

    • 栈地址

    • 栈保护区大小

终止线程 pthread_exit():


  • 线程在以下几种情况下会终止:

    • 线程从其start_routine正常返回,其工作全部完成

    • 线程调用了pthread_exit(),无论其工作是否完成

    • 线程被其他线程通过调用pthread_cancel()取消

    • 线程所在的进程调用了exec() 或者 exit()

    • main()函数结束

  • pthread_exit()允许程序员指定一个可选的终止状态参数。这个可选的参数通常将返回线程“加入”终止线程。

  • pthread_exit()不会关闭文件,任何在线程内打开的文件在线程通过调用pthread_exit()终止后仍继续保持打开状态。

线程的创建和终止示例代码


  • 在这个简单的例子中将通过调用prhtread_ctreate()建立5个线程,每个线程输出“Hello
    World!”,然后调用pthread_exit()终止。这里是结果


  •  1 #include <pthread.h>
    2 #include <stdio.h>
    3 #define NUM_THREADS 5
    4
    5 void *PrintHello(void *threadid)
    6 {
    7 long tid;
    8 tid = (long)threadid;
    9 printf("Hello World! It‘s me, thread #%ld!\n", tid);
    10 pthread_exit(NULL);
    11 }
    12
    13 int main (int argc, char *argv[])
    14 {
    15 pthread_t threads[NUM_THREADS];
    16 int rc;
    17 long t;
    18 for(t=0; t<NUM_THREADS; t++){
    19 printf("In main: creating thread %ld\n", t);
    20 rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
    21 if (rc){
    22 printf("ERROR; return code from pthread_create() is %d\n", rc);
    23 exit(-1);
    24 }
    25 }
    26
    27 /* Last thing that main() should do */
    28 pthread_exit(NULL);
    29 }


向线程传递参数


  • pthread_create()允许传递一个参数到线程启动时调用的函数即所谓的start_routine。在需要传多个参数的时候,可以通过创建一个封装很多参数的结构体,然后将指向该结构体的指针传给
    pthread_create()就可以了。

  • 所有的参数必须以指针形式传递,同时转为类型为void。

  • 线程传递参数的示例代码:这里是结果


  •  1 /******************************************************************************
    2 * FILE: hello_arg1.c
    3 * DESCRIPTION:
    4 * A "hello world" Pthreads program which demonstrates one safe way
    5 * to pass arguments to threads during thread creation.
    6 ******************************************************************************/
    7 #include <pthread.h>
    8 #include <stdio.h>
    9 #include <stdlib.h>
    10 #define NUM_THREADS 8
    11
    12 char *messages[NUM_THREADS];
    13
    14 void *PrintHello(void *threadid)
    15 {
    16 int *id_ptr, taskid;
    17
    18 sleep(1);
    19 id_ptr = (int *) threadid;
    20 taskid = *id_ptr;
    21 printf("Thread %d: %s\n", taskid, messages[taskid]);
    22 pthread_exit(NULL);
    23 }
    24
    25 int main(int argc, char *argv[])
    26 {
    27 pthread_t threads[NUM_THREADS];
    28 int *taskids[NUM_THREADS];
    29 int rc, t;
    30
    31 messages[0] = "English: Hello World!";
    32 messages[1] = "French: Bonjour, le monde!";
    33 messages[2] = "Spanish: Hola al mundo";
    34 messages[3] = "Klingon: Nuq neH!";
    35 messages[4] = "German: Guten Tag, Welt!";
    36 messages[5] = "Russian: Zdravstvytye, mir!";
    37 messages[6] = "Japan: Sekai e konnichiwa!";
    38 messages[7] = "Latin: Orbis, te saluto!";
    39
    40 for(t=0;t<NUM_THREADS;t++) {
    41 taskids[t] = (int *) malloc(sizeof(int));
    42 *taskids[t] = t;
    43 printf("Creating thread %d\n", t);
    44 rc = pthread_create(&threads[t], NULL, PrintHello, (void *) taskids[t]);
    45 if (rc) {
    46 printf("ERROR; return code from pthread_create() is %d\n", rc);
    47 exit(-1);
    48 }
    49 }
    50
    51 pthread_exit(NULL);
    52 }


传递多个参数的例子,请看这里


Joining and Detaching 线程

pthread_join(threadid,status)
pthread_detach(threadid)
pthread_attr_setdetachstate(attr,detachstate)
pthread_atr_getdetachstate(attr,detachstate)

  • Joining:

    • "Joining"是线程间同步的一种方式。

    • pthread_join()会阻塞调用的线程直至制定的threadid线程终止

    • 如果在指定的目标线程中调用pthread_exit(),程序员可以获得目标线程的终止返回状态。

    • 线程一个创建,其中的一个属性就被制定为joinable或者detached。而且只有joinable的线程才可以使用这种同步方式。

    • 显式的创建一个线程为joinable或者detached,可以在pthread_create()中使用属性参数,步骤如下: 1)
      声明一个线程属性变量,类型为pthread_attr_t 2) 使用pthread_attr_init()初始化属性变量 3)
      使用pthread_attr_setdetachstate()设置属性分离状态 4)
      程序结束时,使用pthread_attr_destroy()释放属性对象使用的资源

    • 还有两种同步方法,互斥锁和条件变量,将在以后的blog中讨论

  • Detaching

    • pthread_detach()可以显式的detach一个线程即便它创建的时候是joinable。

    • 没有相反的API

  • Pthread Joining示例代码如下:这里是结果


     1 /*****************************************************************************
    2 * FILE: join.c
    3 * DESCRIPTION:
    4 * This example demonstrates how to "wait" for thread completions by using
    5 * the Pthread join routine. Threads are explicitly created in a joinable
    6 * state for portability reasons. Use of the pthread_exit status argument is
    7 * also shown. Compare to detached.c
    8 ******************************************************************************/
    9 #include <pthread.h>
    10 #include <stdio.h>
    11 #include <stdlib.h>
    12 #define NUM_THREADS 4
    13
    14 void *BusyWork(void *t)
    15 {
    16 int i;
    17 long tid;
    18 double result=0.0;
    19 tid = (long)t;
    20 printf("Thread %ld starting...\n",tid);
    21 for (i=0; i<1000000; i++)
    22 {
    23 result = result + sin(i) * tan(i);
    24 }
    25 printf("Thread %ld done. Result = %e\n",tid, result);
    26 pthread_exit((void*) t);
    27 }
    28
    29 int main (int argc, char *argv[])
    30 {
    31 pthread_t thread[NUM_THREADS];
    32 pthread_attr_t attr;
    33 int rc;
    34 long t;
    35 void *status;
    36
    37 /* Initialize and set thread detached attribute */
    38 pthread_attr_init(&attr);
    39 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    40
    41 for(t=0; t<NUM_THREADS; t++) {
    42 printf("Main: creating thread %ld\n", t);
    43 rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t);
    44 if (rc) {
    45 printf("ERROR; return code from pthread_create() is %d\n", rc);
    46 exit(-1);
    47 }
    48 }
    49
    50 /* Free attribute and wait for the other threads */
    51 pthread_attr_destroy(&attr);
    52 for(t=0; t<NUM_THREADS; t++) {
    53 rc = pthread_join(thread[t], &status);
    54 if (rc) {
    55 printf("ERROR; return code from pthread_join() is %d\n", rc);
    56 exit(-1);
    57 }
    58 printf("Main: completed join with thread %ld having a status of %ld\n",t,(long)status);
    59 }
    60
    61 printf("Main: program completed. Exiting.\n");
    62 pthread_exit(NULL);
    63 }


POSIX 线程编程(二)线程建立与终止,布布扣,bubuko.com

时间: 2025-01-16 13:13:44

POSIX 线程编程(二)线程建立与终止的相关文章

线程篇(二)

C# 温故而知新: 线程篇(二) 线程池和异步线程 目录: 1 什么是CLR线程池? 2 简单介绍下线程池各个优点的实现细节 3 线程池ThreadPool的常用方法介绍 4 简单理解下异步线程 5 异步线程的工作过程和几个重要的元素 6 有必要简单介绍下Classic Async Pattern 和Event-based Async Pattern 7 异步线程的发展趋势以及.net4.5异步的简化 8 本章示例 自定义一个简单的线程池 Asp.net异步IHttpAsyncHandler示例

Posix线程编程指南(1)

Posix线程编程指南(1) 作者:杨沙洲 原文地址:http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part1/ 线程创建与取消 这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第一篇将向您讲述线程的创建与取消. 1 线程创建 1.1 线程与进程 相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有

Posix线程编程指南(5)

Posix线程编程指南(5) 杨沙洲 原文地址:http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part5/ 杂项 这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第五篇将向您讲述pthread_self().pthread_equal()和pthread_once()等杂项函数. 在Posix线程规范中还有几个辅助函数难以归类,暂且称其为杂项函数,主要包

Posix线程编程指南(4)

Posix线程编程指南(4) 杨沙洲 原文地址:http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part4/ 线程终止 这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第四篇将向您讲述线程中止. 线程终止方式 一般来说,Posix的线程终止有两种情况:正常终止和非正常终止.线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退

POSIX 线程编程(一)简介

简介 在共享内存的多处理器结构中,可以用线程来实现并行.对于UNIX系统, IEEE POSIX 1003.1c标准规定了C语言线程编程接口的标准.这份标准的实现就是POSIX threads, 或者称为Pthreads. 本文开始先介绍线程的基本概念,动机和设计方面的一些考虑. 接下来是Pthreads API 的三个主要部分:线程管理,互斥锁和 条件变量.本文自始至终会贯穿大量的示例代码来展示如何使用Pthread API的每一部分. Pthreads 概述 线程是什么? 从技术角度讲,一个

Posix线程编程指南(2)

Posix线程编程指南(2) 杨沙洲 原文地址:http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part2/ 线程私有数据 这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第二篇将向您讲述线程的私有数据. 概念及作用 在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据.在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程

Unix环境高级编程(十二)线程控制

本章介绍了一个进程中多个线程之间如何保持数据的似有性及进程的系统调用如何与线程进行交互. 1.线程限制: Single Unix定义了一线线程操作的限制,和其他的限制一样,可以通过sysconf来查询.和其它的限制使用目的一样,为了应用程序的在不同操作 系统的可移植性. 一些限制: PTHREAD_DESTRUCTOR_ITERATIONS: 销毁一个线程数据最大的尝试次数,可以通过_SC_THREAD_DESTRUCTOR_ITERATIONS作为sysconf的参数查询. PTHREAD_K

Posix线程编程指南(3)

Posix线程编程指南(3) 杨沙洲 原文地址:http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part3/ 线程同步 这是一个关于Posix线程编程的专栏.作者在阐明概念的基础上,将向您详细讲述Posix线程库API.本文是第三篇将向您讲述线程同步. 1 互斥锁 尽管在Posix Thread中同样可以使用IPC的信号量机制来实现互斥锁mutex功能,但显然semphore的功能过于强大了,在Posix Thr

并发编程 15—— 线程池 之 原理二

Java并发编程实践 目录 并发编程 01—— ConcurrentHashMap 并发编程 02—— 阻塞队列和生产者-消费者模式 并发编程 03—— 闭锁CountDownLatch 与 栅栏CyclicBarrier 并发编程 04—— Callable和Future 并发编程 05—— CompletionService : Executor 和 BlockingQueue 并发编程 06—— 任务取消 并发编程 07—— 任务取消 之 中断 并发编程 08—— 任务取消 之 停止基于线