Chinaunix首页 | 论坛 | 博客
  • 博客访问: 451773
  • 博文数量: 72
  • 博客积分: 3186
  • 博客等级: 中校
  • 技术积分: 1039
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-07 16:53
文章分类

全部博文(72)

文章存档

2012年(1)

2011年(5)

2010年(10)

2009年(56)

我的朋友

分类: LINUX

2010-02-05 16:37:13

对于系统调用和库函数,这里统称为函数,毕竟对于上层使用它们来说,无需关心它们的细节。


1. 什么是线程
一个进程在同一时刻只做一件事,引入了多线程之后,则在单进程环境中可同时执行多个任务,即
每个线程完成各自的任务,这样显得进程在同一时刻可以做多件事情。
线程的引入可以简化程序结构,在一个线程阻塞的时候可以执行其他的线程,提高了cpu的利用效
率,改善了程序的响应时间和吞吐量。
线程所包含的信息包括:
        线程ID
        一组寄存器值
        栈
        调度优先级和策略
        信号屏蔽字
        errno变量
        线程私有数据
        ...
进程的所有信息对其中的线程都是共享的,如可执行程序文本、程序的全局内存和堆内存、栈、文
件描述符。
程序中可使用
        #ifdef _POSIX_THREADS
来测试系统是否支持线程。

线程带来的好处:
      o 为不同的事件分配单独的线程,简化处理异步事件的代码
      o 同一进程中的多个线程可以简单的共享资源,而进程间的内存和文件描述符的共享需要
        使用操作系统提供的复杂机制。
      o 将一个问题分解为多个线程来处理,每个线程处理其中的一个任务,改善整个程序的吞
        吐量。
      o 交互的程序通过使用多线程来改善响应时间,如将程序中的用户输入输出部分与处理部
        分分开。

2. 线程标识
每个线程都有一个线程ID,这个线程ID只在该线程所属的进程环境中有效,其数据类型为
        pthread_t
这样就将线程ID的类型抽象出来,至于具体的实现,pthread_t可以实现为一个结构类型,也可实
现为一个非负整数。在我的系统中,/usr/include/bits/pthreadtypes.h文件中可以看到
        typedef unsigned long int pthread_t;
说明在Linux中用一个非负整数来表示线程ID。

由于可移植性的要求,无法预知pthread_t类型的实现(它是一个整数还是一个结构体,或是其他),
所以无法直接来对两个线程的ID进行比较。就像无法直接对两个字符串直接进行比较一样(需要使用
strcmp函数),也需要调用一个函数来完成线程ID的比较
        #include
        int pthread_equal(pthread_t tid1, pthread_t tid2);
        若相等则返回非0,否则返回0

一个线程获得其自身的线程ID
        #include
        pthread_t pthread_self(void);
        返回线程ID

3. 创建线程
进程的创建使用fork函数,线程的创建使用pthread_create函数。
        #include
        int pthread_create(pthread_t *restrict thread,
                           const pthread_attr_t *restrict attr,
                           void *(*start_routine)(void *),
                           void *restrict arg
                          );
(其中restrict是C99中定义的一个关键字)

该函数会在进程中创建一个新线程,函数的各参数描述如下:
      o 第一个参数thread是一个指向pthread_t对象的指针,当线程成功创建后,新线程
        的ID会存储在thread指向的pthread_t对象中。
      o 第二个参数attr,指定新建线程的属性。如果attr为NULL,则创建线程时使用默认的属
        性。线程创建完成之后仍可使用相关函数来改变线程的属性,
      o 第三个参数start_routine是一个函数指针(即函数的首地址),它是新建线程的入口,新
        创建的线程从start_routine这个地址开始运行。从上面的定义来看,该函数指针所指向
        的函数有两个特征:
                        函数返回值为 void * 类型
                        该函数有一个类型为 void * 类型的参数
      o 第四个参数arg。start_routine所指向的函数有一个类型为 void * 的参数,即为这里
        的 void *arg

返回值:
        如果线程创建成功,则pthread_create函数返回0;否则返回一个非0值,该非0值是代
        表一个错误码来指示出错类型。

返回值的错误码有如下几种:
      o EAGAIN 不能获取(gain)到新线程所需的资源,或进程中的线程数量已达到了所允许的
        最大值(PTHREAD_THREADS_MAX)
      o EINVAL 创建时指定的属性attr无效(invalid)
      o EPERM 线程的创建者没有相应的权限


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

pthread_t ntid;

void
err_sys(const char *s)
{
        printf("%s\n", s);
        exit(1);
}

void
printids(const char *s)
{
        pid_t pid;
        pthread_t tid;

        pid = getpid();
        tid = pthread_self();
        printf("%s pid %u tid %u (0x%x) \n", s,
                (unsigned int)pid,
                (unsigned int)tid,
                (unsigned int)tid);
}

void *
thr_fn(void *arg)
{
        printids("new thread:");
        return ((void *)0);
}

int
main(void)
{
        int err;

        err = pthread_create(&ntid, NULL, thr_fn, NULL);
        if (err != 0)
                err_sys("pthread_create error\n");
        printids("main thread:");
        sleep(1);

        exit(0);
}


编译
        gcc -Wall test.c -lpthread
        不要忘记链接线程库

./a.out (执行结果如下)
new thread: pid 30381 tid 3085904784 (0xb7ef2b90)
main thread: pid 30381 tid 3085907648 (0xb7ef36c0)

疑问:
        观察程序执行结果,与apue2上面所描述的Linux下执行结果有两点差别:

      o 这里两个线程的pid相同(说明是同一个进程)
        而书中所叙述的是:Linux使用clone系统调用来实现pthread_create,clone用于创建
        子进程。按书所说,主线程和新线程的pid应该不同(书上的结果确实是不同pid)。

      o Linux里pthread_t实现为unsigned long int,但这里打印出来的线程ID值看起来十六
        进制的表示更有意义些,这是为何?

Linux 线程模型的比较:LinuxThreads 和 NPTL
阅读(5510) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

sandflee2010-03-07 22:41:39

现在linux里getpid返回的是线程组id,不是进程id