T9的空间

You will never walk alone!

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  69 随笔 :: 0 文章 :: 28 评论 :: 0 Trackbacks

线程函数
int pthread_equal(pthread_t tid1, pthread_t tid2)
pthread_t pthread_self(void)

int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr
     void* (*start_rtn)(void), void* restrict arg)

thread被创建的时候会继承调用线程的浮点环境和信号屏蔽字,但是该线程的未决信号集将会被清楚,
清除未决信号集这件事情应该是没有疑问的,在thread创建之前pending住的信号,不应该deliver给下一个
Ps: 线程的浮点环境指的是啥? 看来以后我应该去注意下浮点数的运算原理。

pthread相关的函数会直接返回错误码,而不会和一些system call一样,置全局errno,两种方式都有好处,一个可以讲返回值
带回的错误代码集中起来,范围缩小;另外一个非常方便,关键点在于这一类共用errno的是否真的异常是可以共用的。

pthread_create返回之前有可能新的线程就已经开始run了

启动函数 void* (*start_rtn)(void)

可以通过return给回来,也可以通过pthread_exit给
这个会存在一个地方
通过pthread_join(tid, void**)取回来

这里join的和java join是一样的功能

如果这个东西是一个很大的东西:),那么放到heap是最好的选择,不要放到stack上了,不然线程返回这东西就没了,join取到的内存地址就变成一个无效的了,SIGSEGV就会被发出来

pthread_cancel,同一个进程可以call,提出请求终止线程

pthread_cleanup_push
pthread_cleanup_pop

线程分离,这样子线程终止后可以释放一些资源,而不用一定要其他人来join
方法有两种,新建的时候加上分离属性
    pthread_attr_init (&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);

或者call pthread_detach(pthread_t tid)

线程互斥与同步

typedef struct
{
    
int volatile value;
}
 pthread_mutex_t;

多注意volatile变量,这个东西理论上就是让编译器不要做优化,不要cache volatile类型的变量,
每次都去内存地址中拿,而不是寄存器/高速缓存副本,这种变量极容易被编译器不知道的人改变,例如其他线程。

静态初始化:
#define  PTHREAD_MUTEX_INITIALIZER             {0}
#define  PTHREAD_RECURSIVE_MUTEX_INITIALIZER   {0x4000}
#define  PTHREAD_ERRORCHECK_MUTEX_INITIALIZER  {0x8000}
所谓的动态初始化
pthread_mutex_init; pthread_mutex_destroy

然后就是一些pthread mutex的基本处理函数了
lock,unlock
trylock;

这个trylock需要好好理解下,尝试获取lock,如果OK,那么lock他然后 return 0; 否则也不会suspend住,而是直接返回EBUSY

pthread_mutex_destroy, 会先去try lock,然后处理掉这个mutex的值。

这里稍微提一下

int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
    
int mtype, tid, oldv, shared;

    
if (__unlikely(mutex == NULL))
        
return EINVAL;

    mtype  
= (mutex->value & MUTEX_TYPE_MASK);
    shared 
= (mutex->value & MUTEX_SHARED_MASK);

    
/* Handle common case first */
    
if ( __likely(mtype == MUTEX_TYPE_NORMAL) )
    
{
        
if (__atomic_cmpxchg(shared|0, shared|1&mutex->value) == 0{
            ANDROID_MEMBAR_FULL();
            
return 0;
        }


        
return EBUSY;
    }




__likely/__unlikely函数用来告诉编译器优化代码,类似if else中最有可能or最没有可能发生的Case

mutex就有deadlock的问题,单线程,如果有代码重入重复获取锁就会deadlock,因为你走不到你unlock的地方去;另外
常见的deadlock就是lock比较多,又没有设计好顺序,这个应该从业务逻辑上就应该定义好,当然有时候有的人用的时候or改代码的时候
并没有理清这些lock的关系,是否有dependency,比较难通过借用一些编译系统来Cover住,然后改完就有bug。

然后还有一种需要设计好的是锁的粒度
太粗太细都不好
粒度太粗,lock住的东西太多,很多线程都要等lock,最后这个东西会演变成一个串行的东西
粒度太细,lock又变的太多,不停的需要lock/unlock,performance就会变差。
目前看到的Android上的很多lock都太粗。

rw锁 ->读写锁
基本理念就是读不会影响临界区发生变化
所以读模式的rw lock可以多个人占用,写模式的rw lock时能被一个线程lock

只要有写模式lock请求,那么后面的读模式lock请求一般实现是都会被Suspend住,不然因为读模式下,可以重复lock,如果不
suspend,那么写模式的lock请求有可能永远得不到相应。
rw锁一般用在 read比 write行为多的多的场景,允许多线程并发去读,单一线程去写。

然后会想到spinlock,可以去网上search看下基本概念,spinlock一般在SMP架构下会比较有效果。

mutex是一种同步机制or讲这是一种互斥机制 -> Java synchronize
还一种就是条件变量 condition.. -> wait/notify

这里有段话很好
条件变量给多个线程提供了一个回合的场所,条件变量与互斥量一起使用的时候,允许线程以无竞争方式等待特定的条件发生。

作业:
1.线程之间传递数据不要用stack变量,用放到下面这些地方的变量就好,RW/RO/ZI/Heap就没事了
4.
现在一般都是这样

    pthread_mutex_lock(&s_startupMutex);

    s_started = 1;
    pthread_cond_broadcast(&s_startupCond);

    pthread_mutex_unlock(&s_startupMutex);

会在broadcast后才unlock
否则有比较高的概率,unlock后,被其他线程将条件改掉,这个时候broadcast出去就没有意义了。
但是这种也有可能会被另外一个线程,并非wait在那里的线程改变条件值

所以 pthread_cond_wait 返回并不意味着条件一定为真了
最好是always check条件
类似这种
    while (s_started == 0) {
        pthread_cond_wait(&s_startupCond, &s_startupMutex);
    }

posted on 2013-06-03 17:03 Torres 阅读(171) 评论(0)  编辑 收藏 引用 所属分类: APUE

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理