关于一个消费者模式,,,引起的问题..
我在io线程里不断的把一个函数调用放到队列里
然后ruby线程就不断的从这个队列里取出函数之争并执行.
典型的 消费者模式.
我以前以为是这样...
这是work线程
pthread_mutex_lock(&mutex2)
while(( invoke = get_invoke() ) != NULL){
do_invoke(invoke);
}
pthread_mutex_unlock(&mutex2)
pthread_cond_wait(&cond, &mutex);
这里是io线程
pthread_mutex_lock(&mutex2);
push_invoke(invoke);
pthread_mutex_unlock(&mutex2);
pthread_cond_signal(&cond);// 本意是打算在这里唤醒线程
但是会出现一个情况..就是在
pthread_mutex_unlock(&mutex2); // 这里解锁,也就是说 上面的线程就会开始执行
pthread_cond_signal(&cond);// 本意是打算在这里唤醒线程
这里..在unlock的时候..很有可能work线程已经解锁了...一旦 work 比较耗时..那么就会出现..
先 执行 io线程的 pthread_cond_signal 然后再执行 pthread_cond_wait
因为先pthread_cond_signal后pthread_cond_wait ..那么 pthread_cond_signal 就变得无效了
肯定会问.为什么 不先wait 再 unlock ,..但是这样会出现 io 线程一直处于无法进入的状态...
那么解决方法如下:
就是 mutex_lock 直接使用跟cond_wait 配套的互斥锁..
work thread
pthread_mutex_lock(&mutex)
while(( invoke = get_invoke() ) != NULL){
do_invoke(invoke);
}
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex)
io thread
pthread_mutex_lock(&mutex);
push_invoke(invoke);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
注意.顺序换了.然后互斥锁换了同一个.
肯定会问..那如果上面的开始等待后..那下面岂不是一直进去..无法解锁?.
但其实是这样的..
man 了一下 pthread_cond_wait
其实是会先把mutex 给解锁..然后在阻塞..!!这里是重点,,
他会把mutex给unlock..那么.就可想而知了.
io线程解锁.再通过 signal 唤醒上面的线程 :)
事实就是这样...多看文档...经验不代表一切...
下面是项目代码
pthread_mutex_t pthread_ruby_invoke_call_invoke_mutex;
pthread_cond_t pthread_ruby_invoke_call_invoke_cond;
struct fs_loop_queue* ruby_invoke_loop_que;
void
fs_rb_loop(const char* main_file, int pathc, const char** pathv){
for(int i = 0 ; i < pathc ; i++){
char path[128];
snprintf(path, 128, " $: << '%s' ", pathv[i]);
rb_eval_string(path);
}
ruby_invoke_loop_que = fs_create_loop_queue(INVOKE_LEN);
pthread_mutex_init(&pthread_ruby_invoke_call_invoke_mutex, NULL);
pthread_cond_init(&pthread_ruby_invoke_call_invoke_cond, NULL);
int ret = 0;
rb_load_protect(rb_str_buf_new_cstr(main_file), 0, &ret);
if(ret != 0){
rb_p(rb_errinfo());
}
struct fs_invoke_call_function* invoke = NULL;
do{
retry:
while((invoke = fs_ruby_pop_call_invoke()) != NULL){
invoke->func((VALUE)invoke->argv);
fs_free(invoke->argv);
fs_free(invoke);
}
pthread_mutex_lock(&pthread_ruby_invoke_call_invoke_mutex);
// 过了临界点.发现有数据,就回去/// 效率 * 2 .....XDDD
if(!fs_loop_queue_empty(ruby_invoke_loop_que)){
pthread_mutex_unlock(&pthread_ruby_invoke_call_invoke_mutex);
goto retry;
}
pthread_cond_wait(&pthread_ruby_invoke_call_invoke_cond,
&pthread_ruby_invoke_call_invoke_mutex);
pthread_mutex_unlock(&pthread_ruby_invoke_call_invoke_mutex);
}while (fs_true);
}
fs_bool
fs_ruby_invoke(struct fs_invoke_call_function* invoke){
pthread_mutex_lock(&pthread_ruby_invoke_call_invoke_mutex);
fs_bool ret = fs_false;
ret = fs_loop_queue_push(ruby_invoke_loop_que, invoke);
if(ret){
pthread_cond_signal(&pthread_ruby_invoke_call_invoke_cond);
}else{
do{
ret = fs_loop_queue_push(ruby_invoke_loop_que, invoke);
pthread_cond_signal(&pthread_ruby_invoke_call_invoke_cond);
}while (!ret);
}
pthread_mutex_unlock(&pthread_ruby_invoke_call_invoke_mutex);
return fs_true;
}
struct
fs_invoke_call_function* fs_ruby_pop_call_invoke(){
struct fs_invoke_call_function* func = (struct fs_invoke_call_function*)fs_loop_queue_pop(ruby_invoke_loop_que);
return func;
}
pthread_mutex_unlock(&mutex2)