文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>Unix编程 线程局部存储和线程同步

Unix编程 线程局部存储和线程同步

时间:2010-09-10  来源:kgisme170

Unix编程 线程局部存储和线程同步
1. 线程局部存储: 不同的线程访问一个同名的变量,这个变量在不同的线程里面对应不同的实例。显然这个变量不能是平凡的,必须用pthread_create_key来创建一个资源表示。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
pthread_key_t key;
void print(){printf("%s\n",(char*)pthread_getspecific(key));}
extern "C" void* t(void* arg){
  pthread_setspecific(key,arg);
  while(1){
    print();
    sleep(1);
  }
  return NULL;
}
int main(void){
  pthread_t pa,pb;
  pthread_key_create(&key,NULL);
  pthread_create(&pa,NULL,t,(void*)"Thread a");
  pthread_create(&pb,NULL,t,(void*)"Thread b");
  pthread_join(pa,NULL);
  pthread_join(pb,NULL);
  return 0;
}

        上面的程序里面用到了pthread_join。这是为了防止在一般情况下,如果朱线程退出了,那么所有的子线程也都跟着退出。man上面对于pthread_join的解释是,阻赛主线程的运行,直到join的线程全部运行完毕。

DESCRIPTION
     The  pthread_join() function suspends processing of the cal-
     ling  thread  until the target thread completes. thread must
     be a member of the  current  process  and  it  cannot  be  a
     detached or daemon thread. See pthread_create(3THR).

        在windows环境下由于没有pthread_join这样原语,所以只能用WaitForSingleObject来等待线程退出。由于Windows核心对象都是可以"等待"的handle,所以WaitForSingleObject是一个无敌的通用函数。

#include"stdafx.h"
#include<windows.h>
#include<conio.h>
HANDLE hm;
void* t(void*s){
  printf("enter thread\n");
  WaitForSingleObject(hm,INFINITE);
  printf("end thread\n");
  return 0;
}
int main()
{
  HANDLE ht=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)t,(LPVOID)("thread 1"),0,0);
  hm=CreateMutex(0,TRUE,0);
  Sleep(1000);
  WaitForSingleObject(ht,1000);
  TerminateThread(ht,1);
  return 0;
}

2. 如果不用线程局部存储,那么为了防止访问冲突,就必须使用线程同步。Posix里面只有信号量没有互斥体(虽然Linux实现了futext),只有pthread线程库里面实现了mutex的语义。下面的程序保证了每次打印的结果,不会互相冲突。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
pthread_mutex_t share=PTHREAD_MUTEX_INITIALIZER;
void print(char* s){printf("%s\n",s);}
extern "C" void* t(void* arg){
  while(1){
    pthread_mutex_lock(&share);
    print((char*)arg);
    pthread_mutex_unlock(&share);
    sleep(1);
  }
  return NULL;
}
int main(void){
  pthread_t pa,pb;
  pthread_create(&pa,NULL,t,(void*)"Thread a");
  pthread_create(&pb,NULL,t,(void*)"Thread b");
  getchar();
  return 0;
}

3. 线程等待
        下面的例子表示了pthread如何用mutex进行等待。注意假如在子线程tb代码里面,如果只有一句pthread_cond_signal(&cond);会怎么样? 因为pthread_cond_signal函数调用,并不是操作系统当中的一个"原子",也就是说,很可能第一个线程ta调用pthread_cond_wait的过程当中,signal被触发了,然后cond_wait状态才达到。这就相当于丢失了signal。所以,在cond_signal之前必须mutex_lock,保证是ta线程的cond_wait执行完毕了释放了mutex,tb才能得到这个锁,进而执行cond_signal。ta再得到signal,函数pthread_cond_wait返回。这里,mutxt的"加锁解锁"和"得到锁释放锁"是两组不同的概念。pthread_mutex_lock要"得到"锁才能"加锁"。而pthread_cond_wait执行的过程是先得到锁,设置cond_wait状态等待signal到来,然后把继续把mutex设置为加锁状态,直到signal带来才退出和释放锁。得到锁和释放锁是操作系统的原语,是不会冲突的。pthread的信号量是对这原语的包装,不是原子操作。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
pthread_mutex_t share=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond;
extern "C" void* ta(void* arg){
  pthread_mutex_lock(&share);
  pthread_cond_wait(&cond,&share);
  pthread_mutex_unlock(&share);
  return 0;
}
extern "C" void* tb(void* arg){
  pthread_mutex_lock(&share);
  pthread_cond_signal(&cond);
  pthread_mutex_unlock(&share);
  return 0;
}
int main(void){
  pthread_t pa,pb;
  pthread_create(&pa,NULL,ta,(void*)"Thread a");
  pthread_create(&pb,NULL,tb,(void*)"Thread b");
  getchar();
  return 0;
}

        当然,这还不够,如果还有一个线程执行了pthread_cancel(&pa)的话,会发生什么事情? ta中的pthread_cond_wait强制退出了,可是现在它受理还拿着锁呢(锁着的),没有解锁,那么tb就永远无法用pthread_mutex_lock得到锁并加锁了,tb永远都不会被执行。
        解决的办法是这样的,类似main函数执行可以注册atexit出口一样,一个线程函数也可以用pthread_cleanup_push来注册一个线程强制退出时,应该再做什么事情。像下面这样。当然,如果线程没有强制退出,记住要删除这个注册信息。把ta的

void myexit(void*){
  pthread_mutext_unlock(&share);
}
extern "C" void* ta(void* arg){
  pthread_cleanup_push(myexit,NULL);
  pthread_mutex_lock(&share);
  pthread_cond_wait(&cond,&share);
  pthread_mutex_unlock(&share);
  pthread_cleanup_pop(0);
  return 0;
}

         pthread_cond_wait可以用条件指示符,来实现程序当中"当某个条件符合的时候,程序才往下进行"这样的,类似Lisp/schema语言的Continuation的功能。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
int x,y;
pthread_mutex_t share=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
extern "C" void* ta(void* arg){
  printf("enter ta\n");
  pthread_mutex_lock(&share);
  while(x<=y){
    printf("ta while\n");
    pthread_cond_wait(&cond,&share);
  }
  printf("x=%d,y=%d\n",x,y);
  x=4;
  y=5;
  pthread_mutex_unlock(&share);
  return 0;
}
extern "C" void* tb(void* arg){
  printf("enter tb\n");
  pthread_mutex_lock(&share);
  x=9;
  y=8;
  printf("tb\n");
  if(x>y)pthread_cond_broadcast(&cond);
  return 0;
}
int main(void){
  x=2;
  y=3;
  pthread_t pa,pb;
  pthread_create(&pa,NULL,ta,(void*)"Thread a");
  pthread_create(&pb,NULL,tb,(void*)"Thread b");
  getchar();
  return 0;
}

         ta的while循环干了什么事情呢? 首先检查条件x<=y,进入pthread_cond_wait,cond_wait对cond加锁,对mutex解锁。然后再次进入while,这个cond是锁定了的,所以第二次pthread_cond_wait等待。然后tb得到锁,线程运行,他设置了x>y,然后pthread_cond_broadcast,这使得ta当中的cond被解锁,同时pthread_cond_wait得到signal执行结束的时候,会再次对mutex加锁(避免别人再得到锁)。再次进入while循环不符合了,退出while。执行ta中下面的程序(此时其他的没有锁的程序不能影响x和y)。
         pthread的设计,看起来不如win下面的thread。它的语义太难理解了,就像谜语一样。

相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载