Linux线程经验

 

pthread线程使用小结

1.奇怪的线程参数初始化

for( i=0; i<n; i++)

{

//会有什么问题?

pthread_create(&tid,NULL, &thread_client_function, (void*)&i );

}

上面代码应该很容易明白,创建多个线程,传入序列号作为线程id。基实这里存在一个大bug, 传递的参数会不成功!!

示例代码:

#include <stdio.h>   #include <stdlib.h>   #include <unistd.h>   #include <pthread.h>   #include <memory.h>   void* thread_client_function( void* param )   {   int client_id = *(int*)param;   printf("client id %d\n", client_id);   }   int main( int argc, char * argv[] )   {   int n = atol( argv[1] );   int i=0;   pthread_t tid;   for( i=0; i<n; i++)   {   pthread_create(&tid,NULL, &thread_client_function, (void*)&i );   }   pthread_join( tid, NULL );   return 0;   }   

 

输出:

gcc -o test_thread test_thread.c -lpthread

./test_thread 3

client id 3

client id 3

client id 3

 

为什么呢?注意其实传递时i是局部变量,而线程的创建是有延时的,所以当多次调用时,线程函数还没执行。但是这里i已经为3了。当线程函数开始执行,读入的参数自然都为3了,这个小细节真可谓令我大伤脑筋呀:)

稍作修改即可:

...

int * a = (int*)malloc( n* sizeof(int) );

for( i=0; i<n; i++)

{

a[i] = i;

pthread_create(&tid,NULL, &thread_client_function, (void*)&a[i] );

}

pthread_join( tid, NULL );

...

这样就可以保存参数不变了。

 

2. pthread_mutex_t / pthread_cond_t初始化/释放

作为一个全局变量时可以使用:

pthread_mutex_t g_mtx = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t g_cond = PTHREAD_COND_INITIALIZER;

 

如果有多个可使用:

pthread_mutex_init( &g_mtx , NULL);

pthread_cond_init( &g_cond , NULL);

 

释放:

pthread_mutex_destroy( &g_mtx );

pthread_mutex_destroy( &g_mtx );

 

3. 同步条件pthread_cond_t使用

1)需要配合mutex使用

pthread_mutex_lock( &g_mtx );

pthread_cond_wait( &g_cond , &g_mtx );

pthread_mutex_unlock( &g_mtx );

使用pthread_cond_wait 需要在 lock/unlock 之间,以防止在进入wait状态前有signal。需要先lock, 一旦进行wait状态,会释放 mutexlock。而一旦有收到signal信号就会自动重新获到mutexlock。而且condlock是原子操作。

在需要的地方进行 pthread_cond_signal( g_cond ), 之前的wait 位置就可以执行,达到多个线程同步。

 

2)使用超时条件

struct timespec tv;

tv.tv_sec = time(0) + 1;

tv.tv_nsec = 0;

ret = pthread_cond_timedwait( &g_cond , &g_mtx ,&tv );

指定超时结构体timespec,注意超时时间是当前时间,所以要设定为time(0) + N秒。timespec 可精确到纳秒。

 

3)多个线程串行执行

只需要在全局设定一个处理序列号,这样每个线程在执行前判断是否为自己要处理的序号,否则继续wait, 处理框架如下:

void* thread_client_function( void* param )

{

int client_id = *(int*)param;

...

do

{

pthread_cond_wait( &g_conds[ i + 1 ] , &g_mtxs[i] );  //等待取得执行信号

}

while ( g_do[client_id][i] != g_idx ); //判断是否为当前处理序列,否则继续等待

...

}

 

void* thread_server_function( void* param )

{

...

for(i=0;i<n; i++ )

{

printf("Server signal %d\n", i + 1 );

pthread_cond_signal( &g_conds[ i + 1 ] ); //唤醒多个处理线程

}

...

}

上面使用了多个cond的处理,也可以直接使用一个cond, 使用pthread_cond_broadcast响醒所有等待的线程。

 

       就是说pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)函数传入的参数mutex用于保护条件,因为我们在调用pthread_cond_wait时,如果条件不成立我们就进入阻塞,但是进入阻塞这个期间,如果条件变量改变了的话,那我们就漏掉了这个条件。因为这个线程还没有放到等待队列上,所以调用pthread_cond_wait前要先锁互斥量,即调用pthread_mutex_lock(),pthread_cond_wait在把线程放进阻塞队列后,自动对mutex进行解锁,使得其它线程可以获得加锁的权利。这样其它线程才能对临界资源进行访问并在适当的时候唤醒这个阻塞的进程。当pthread_cond_wait返回的时候又自动给mutex加锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值