Chinaunix首页 | 论坛 | 博客
  • 博客访问: 532823
  • 博文数量: 137
  • 博客积分: 3170
  • 博客等级: 中校
  • 技术积分: 1455
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-17 11:47
文章分类

全部博文(137)

文章存档

2015年(2)

2013年(1)

2012年(6)

2011年(5)

2010年(62)

2009年(61)

我的朋友

分类: LINUX

2010-11-02 09:10:25

节选修改自: 总裁/CEO, Gentoo Technologies, Inc.的经典系列文章。
POSIX(可移植操作系统接口) THREAD
1.为何要使用线程?
如同进程,线程由内核按时间分片进行管理。在单处理器系统中,内核使用时间分片来模拟线程的并发执行,这种方式和进程的相同。而在多处理器系统中,如同多个进程,线程实际上一样可以并发执行。
多线程比多个独立的进程更优越?线程共享相同的内存空间。不同的线程可以存取内存中的同一个变量。所以,程序中的所有线程都可以读或写声明过的全局变量。如果曾用fork()编写过重要代码,就会认识到这个工具的重要性。为什么呢?虽然fork()允许创建多个进程,但它还会带来以下通信问题: 如何让多个进程相互通信,这里每个进程都有各自独立的内存空间。对这个问题没有一个简单的答案。虽然有许多不同种类的本地 IPC (进程间通信),但它们都遇到两个重要障碍:第一:强加了某种形式的额外内核开销,从而降低性能;第二:对于大多数情形,IPC 不是对于代码的“自然”扩展。通常极大地增加了程序的复杂性。使用进程的问题: 开销和复杂性都非好事。如果曾经为了支持 IPC 而对程序大动干戈过,那么您就会真正欣赏线程提供的简单共享内存机制。由于所有的线程都驻留在同一内存空间,POSIX 线程无需进行开销大而复杂的长距离调用。只要利用简单的同步机制,程序中所有的线程都可以读取和修改已有的数据结构。而无需将数据经由文件描述符转储(文件传递信息?)或挤入紧窄的共享内存空间。应该采用单进程/多线程模式而非多进程/单线程模式。多线程/进程更适合于cpu密集型程序,另外,如果要写可移植性好的多线程程序,最好用posix线程。
restrict关键字:它只能修饰指针,并且它修饰的指针变量是唯一可以访问相应内存对象的变量。
2.创建了n个线程,最后如何清理掉?
未对线程做正确的清理,最终会导致
pthread_create() 调用失败。

如果要等待一个线程终止,就必须将线程的
tid 传递给 pthread_join()。线程库无法为您断定 tid。
POSIX
线程标准提供了有效地管理多个线程所需要的所有工具。实际上,没有父/子关系这一事实却为在程序中使用线程开辟了更创造性的方法。例如,如果有一个线程称为线程
1,线程 1 创建了称为线程 2 的线程,则线程 1 自己没有必要调用
pthread_join() 来合并线程
2,程序中其它任一线程都可以做到。当编写大量使用线程的代码时,这就可能允许发生有趣的事情。例如,可以创建一个包含所有已停止线程的全局“死线程列表”,然后让一个专门的清理线程专等停止的线程加到列表中。这个清理线程调用
pthread_join()
将刚停止的线程与自己合并。现在,仅用一个线程就巧妙和有效地处理了全部清理。
3.pthread_mutex_t 互斥对象作用是什么?
当多个线程同时写共享数据时,对共享数据作保护,仅仅锁住共享数据是不够的,需要锁住一个对共享数据的完整的逻辑操作。
 典型的对全局变量myglobal加一操作:

pthread_mutex_lock(&mymutex);
    j=myglobal;
    j=j+1;
    printf(".");
    fflush(stdout);
    sleep(1);
    myglobal=j;
    pthread_mutex_unlock(&mymutex);

如果改为如下,只锁住共享数据myglobal,显然也是不可以保证互斥访问的,必须锁住一个完整的操作。

pthread_mutex_lock(&mymutex);
    j=myglobal;

pthread_mutex_unlock(&mymutex);
    j=j+1;
    printf(".");
    fflush(stdout);
    sleep(1);

pthread_mutex_lock(&mymutex);
    myglobal=j;
pthread_mutex_unlock(&mymutex);


主线程连续创建a,b,c三个线程:


pthread_create( &thread_a, NULL, thread_function, NULL);
    pthread_create( &thread_b, NULL, thread_function, NULL);
    pthread_create( &thread_c, NULL, thread_function, NULL);

注意事项:1.
就在第二个 create() 调用返回后,主线程无法假定是哪一个线程(a 或 b)会首先开始运行。虽然两个线程都已存在,线程 CPU 时间片的分配取决于内核和线程库。至于谁将首先运行,并没有严格的规则。尽管线程 a 更有可能在线程 b 之前开始执行,但这并无保证。对于多处理器系统,情况更是如此。

注意事项:2
不要以代码的粒度是最小的,比如一条汇编语句而拒绝使用互斥对象,现在的处理器架构并非单cpu,架构很复杂,代码要移植性好。

注意事项:3
如果放置了过多的互斥对象,代码就没有什么并发性可言,运行起来也比单线程解决方案慢。如果放置了过少的互斥对象,代码将出现奇怪和令人尴尬的错误。

注意事项:4
多个线程都要锁定一个互斥对象,该对象解锁后,谁将先得到锁定权?
pthread_mutex_trylock() 时将尝试锁定互斥对象。如果互斥对象当前处于解锁状态,那么您将获得该锁并且函数将返回零。然而,如果互斥对象已锁定,这个调用也不会阻塞。当然,它会返回非零的 EBUSY 错误值。然后可以继续做其它事情,稍后再尝试锁定。
条件变量的使用,是一种通知机制?
thread-aware和 thread-ignorant术语
线程安全的数据结构(eg.队列)并不一定非要使线程操作和数据结构杂糅在一起.
pthread_cond_t()应该说是一种通知机制吧?

关于pthread调试:



阅读(935) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-11-02 17:29:19

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com