⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 multithread.txt

📁 Linux下的多线程编程
💻 TXT
📖 第 1 页 / 共 5 页
字号:
        start_routine。用这种办法在运行线程之前对它进行操作(例如改变
        优先级)。分离线程的终止被忽略。
      THR_DETACHED--将新线程分离,使线程一旦终止,其资源可以得到立刻
        回收利用。如果你不需要等待线程结束,设置此标志。
            如果没有明确的同步要求,一个不挂起的,分离的线程可以在它
        的创建者调用的thr_create函数返回之前终止并将线程号和其他资源
        移交给其他线程使用。
      THR_BOUND--将一个新线程永久绑定在一个LWP上(新线程为绑定线程)。
      THR_NEW_LWP--给非绑定线程的同时性等级加1。效果类似于用
        thr_setconcurrency(3T)来增加同时性等级,但是使用
        thr_setconcurrency()不影响等级设置。典型的,THR_NEW_LWP在LWP池
        内增加一个LWP来运行非绑定线程。
            如果你同时指定了THR_BOUND和THR_NEW_LWP,两个LWP被创建,一
        个被绑定在该线程上,另外一个来运行非绑定线程。
      THR_DAEMON--标志新线程为守护线程。当所有的非守护线程退出后进程
        结束。守护线程不影响进程退出状态,在统计退出的线程数时被忽略。
            一个进程可以通过调用exit(2)或者在所有非守护线程调用
        thr_exit(3T)函数终止的时候终止。一个应用程序,或它调用的一个库,
        可以创建一个或多个在决定是否退出的时候被忽略的线程。用
        THR_DAEMON标志创建的线程在进程退出的范畴不被考虑。
    New_thread--在thr_create()成功返回后,保存指向存放新线程ID的地址。
调用者负责提供保存这个参数值指向的空间。
    如果你对这个值不感兴趣,给它赋值0。
    返回值--thr_thread在正常执行后返回0,其他值意味着错误。在以下情况
发生时,函数失败并返回相关值。
        EAGAIN 超过系统限制,例如创建了太多的LWP。
        ENOMEM 内存不够创建新线程。
        EINVAL stack_base非空,但stack_size比thr_minstack()的返回值小。

2.1.11.3 Thr_create(3T)例程

    例2-5显示了怎样用一个与创建者(orig_mask)不同的新的信号掩模来创建
新线程。
    在这个例子当中,new_mask被设置为屏蔽SIGINT以外的任何信号。然后创建
者的信号掩模被改变,以便新线程继承一个不同的掩模,在thr_create()返回后,
创建者的掩模被恢复为原来的样子。
    例子假设SIGINT不被创建者屏蔽。如果最初是屏蔽的,用相应的操作去掉屏
蔽。另外一种办法是用新线程的start routine来设置它自己的信号掩模。
    Code Example 2-5 thr_create() Creates Thread With New Signal Mask
        thread_t tid;
        sigset_t new_mask, orig_mask;
        int error;
        (void)sigfillset(&new_mask);
        (void)sigdelset(&new_mask, SIGINT);
        (void)thr_sigsetmask(SIGSETMASK, &new_mask, &orig_mask):
        error = thr_create(NULL, 0, dofunc, NULL, 0, &tid);
        (void)thr_sigsetmask(SIGSETMASK, NULL, &orig_mask);

2.1.12获得最小堆栈

    thr_min_stack(3T) 用thr_min_stack(3T)来获得线程的堆栈下限
        #include <thread.h>
        size_t thr_min_stack(void);
    thr_min_stack()返回执行一个空线程所需要的堆栈大小(空线程是一个创
建出来执行一个空过程的线程)。
    如果一个线程执行的不仅仅是空过程,应当给它分配比thr_min_stack()返
回值更多的空间。
    如果线程创建时由用户指定了堆栈,用户应当为该线程保留足够的空间。在
一个动态连接的环境里,确切知道线程所需要的最小堆栈是非常困难的。
    大多数情况下,用户不应当自己指定堆栈。用户指定的堆栈仅仅用来支持那
些希望控制它们的执行环境的应用程序。
    一般的,用户应当让线程库来处理堆栈的分配。线程库提供的缺省堆栈足够
运行任何线程。

2.1.13设置线程的同时性等级

2.1.13.1 thr_getconcurrency(3T)

    用thr_getconcurrency()来获得期望的同时性等级的当前值。实际上同时活
动的线程数可能会比这个数多或少。
        #include <thread.h>
        int thr_getconcurrency(void)
    返回值--thr_getconcurrency()为期望的同时性等级返回当前值。

2.1.13.2 Thr_setconcurrency(3T)

    用thr_setconcurrency()设置期望的同时性等级。
        #include <thread.h>
        int thr_setconcurrency(new_level)
    进程中的非绑定线程可能需要同时活动。为了保留系统资源,线程系统的缺
省状态保证有足够的活动线程来运行一个进程,防止进程因为缺少同时性而死锁。
    因为这也许不会创建最有效的同时性等级,thr_setconcurrency()允许应用
程序用new_level给系统一些提示,来得到需要的同时性等级。
    实际的同时活动的线程数可能比new_level多或少。
    注意,如果没有用thr_setconcurrency调整执行资源,有多个
compute-bound(????)线程的应用程序将不能分配所有的可运行线程。
    你也可以通过在调用thr_create()时设置THR_NEW_LWP标志来获得期望的同
时性等级。
    返回值--thr_setconcurrency()在正常执行后返回0,其他值意味着错误。
在以下情况发生时,函数失败并返回相关值。
        EAGAIN 指定的同时性等级超出了系统资源的上限。
        EINVAL new_level的值为负。

2.1.14得到或设定线程的优先级

    一个非绑定线程在调度时,系统仅仅考虑进程内的其他线程的简单的优先级,
不做调整,也不涉及内核。线程的系统优先级的形式是唯一的,在创建进程时继
承而来。

2.1.14.1 Thr_getprio(3T)

    用thr_getprio()来得到线程当前的优先级。
        #include <thread.h>
        int thr_getprio(thread_t target_thread,int *pri)
    每个线程从它的创建者那里继承优先级,thr_getprio把target_thread当前
的优先级保存到由pri指向的地址内。
    返回值--thr_getprio()在正常执行后返回0,其他值意味着错误。在以下情
况发生时,函数失败并返回相关值。
        ESRCH target_thread在当前进程中不存在。

2.1.14.2 Thr_setprio(3T)

    用thr_setprio()来改变线程的优先级。
        #include <thread.h>
        int thr_setprio(thread_t target_thread,int pri)
    
    thr_setprio改变用target_thread指定的线程的优先级为pri。缺省状态下,
线程的调度是按照固定的优先级--从0到最大的整数--来进行的,即使不全由优先
级决定,它也占有非常重要的地位。Target_thread将打断低优先级的线程,而让
位给高优先级的线程。
    
    返回值--thr_setprio()在正常执行后返回0,其他值意味着错误。在以下情
况发生时,函数失败并返回相关值。
        ESRCH target_thread在当前进程中找不到。
        EINVAL pri的值对于和target_thread相关的调度等级来说没有意义。

2.1.15线程调度和线程库函数

    下面的libthread函数影响线程调度

2.1.15.1 thr_setprio()和thr_getprio()
    这两个函数用来改变和检索target_thread的优先级,这个优先级在用户级线
程库调度线程时被引用,但与操作系统调度LWP的优先级无关。
    这个优先级影响线程和LWP的结合--如果可运行的线程比LWP多的时候,高优
先级的线程得到LWP。线程的调度是"专横"的,就是说,如果有一个高优先级的线
程得不到空闲的LWP,而一个低优先级的线程占有一个LWP,则低优先级的线程被
迫将LWP让给高优先级的线程。

2.1.15.2 thr_suspend()和thr_continue()
    这两个函数控制线程是否被允许运行。调用thr_suspend(),可以把线程设置
为挂起状态。就是说,该线程被搁置,即使有可用的LWP。在其他线程以该线程为
参数调用thr_continue后,线程退出挂起状态。这两个函数应当小心使用--它们
的结果也许是危险的。例如,被挂起的线程也许是处在互锁状态的,将它挂起可
能会导致死锁。
    一个线程可以在创建时用THR_SUSPENDED标志设置为挂起。

2.1.15.3 thr_yield()
    Thr_yield函数使线程在相同优先级的线程退出挂起状态后交出LWP。(不会有
更高优先级的线程可运行而没有运行,因为它会通过强制的方式取得LWP)。这个
函数具有非常重要的意义,因为在LWP上没有分时的概念(尽管操作系统在执行LWP
时有分时)。
    最后,应当注意priocntl(2)也会影响线程调度。更详细的内容请参照"LWP和
调度等级"。

发信人: Mccartney (coolcat), 信区: Unix
标  题: Solaris2.4 多线程编程指南4--操作系统编程
发信站: BBS 水木清华站 (Sun May 17 16:31:05 1998)

4. 操作系统编程
    本章讨论多线程编程如何和操作系统交互,操作系统作出什么改变来支持多线
程。
        进程--为多线程而做的改动
        警告(alarm), 计数器(interval timer), 配置(profiling)
        全局跳转--setjmp(3C) 和longjmp(3C)
        资源限制
        LWP和调度类型
        扩展传统信号
        I/O 问题

4.1进程--为多线程而做的改变

4.1.1复制父线程
        fork(2)
    用fork(2)和fork1(2)函数,你可以选择复制所有的父线程到子线程,或者子
线程只有一个父线程???。
    Fork()函数在子进程中复制地址空间和所有的线程(和LWP)。这很有用,例如,
如果子进程永远不调用exec(2)但是用父进程地址空间的拷贝。
    为了说明,考虑一个父进程中的线程--不是调用fork()的那个--给一个互斥锁
加了锁。这个互斥锁被拷贝到子进程当中,但给互斥锁解锁的线程没有被拷贝。所
以子进程中的任何试图给互斥锁加锁的线程永久等待。为了避免这种情况,用fork()
复制进程中所有的线程。
    注意,如果一个线程调用fork(),阻塞在一个可中断的系统调用的线程将返回
EINTR。
        Fork1(2)
    Fork1(2) 函数在子线程中复制完全的地址空间,但是仅仅复制调用fork1()的
线程。这在子进程在fork()之后立即调用exec()时有用。在这种情况下,子进程不
需要复制调用fork(2)函数的那个线程以外的线程。
    在调用fork1()和exec()之间不要调用任何库函数--库函数也许会使用一个由
多个线程操作的锁。

    *Fork(2)和fork1(2)的注意事项
    对于fork()和fork1(),在调用之后使用全局声明时要小心。
    例如,如果一个线程顺序地读一个文件而另外一个线程成功地调用了fork(),
每一个进程都有了一个读文件的线程。因为文件指针被两个线程共享,父进程得到
一些数据,而子进程得到另外一些。
    对于fork()和fork1(),不要创建由父进程和子进程共同使用的锁。这仅发生在
给锁分配的内存是共享的情况下(用mmap(2)的MAP_SHARED声明过)。

        Vfork(2)
    Vfork(2)类似于fork1(),只有调用线程被拷贝到子进程当中去。
    注意,子进程中的线程在调用exec(2)之前不要改变内存。要记住vfork()将父
进程的地址空间交给子进程。父进程在子进程调用exec()或退出后重新获得地址空
间。子进程不改变父进程的状态是非常重要的。
    例如在vfork()和exec()之间创建一个新线程是危险的。

4.1.2执行文件和终止进程

        exec(2)和exit(2)
    exec(2)和exit(2)调用和单线程的进程没有什么区别,只是它们破坏所有线程
的地址空间。两个调用在执行资源(以及活动线程)被破坏前阻塞。
    如果exec()重建一个进程,它创建一个LWP。进程从这个初始线程开始执行程序。
象平时一样,如果初始线程返回,它调用exit()来破坏整个进程。
    如果所有线程退出,进程用0值退出。

4.2 Alarms(闹钟???), Interval Timers(定时器), and Profiling(配置)

    每个LWP有一个唯一的实时的定时器和一个绑定在LWP上的线程的闹钟。定时器

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -