当前位置:首页 > 青鸟知识 > 网络技术

Linux多线程同步的几种体例

来源:北大青鸟新途麓谷 发布日期:2016-05-21
}

编译: g++ -o thread testthread.cpp -lpthread

声明:pthread库不是Linux系统默许的库,毗邻时需求应用静态库libpthread.a,所以在应用pthread_create()树立线程,和挪用pthread_atfork()函数成立fork处置法式时,需求链接该库。在编译中要加 -lpthread参数。

2)前提变量(cond)

   支配线程间同享的全局变量中止同步的一种机制。前提变量上的根基支配有:触发前提(当前提变成 true 时);等待前提,挂起线程直到其他线程触发前提。

int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);  

int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);

int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);

int pthread_cond_destroy(pthread_cond_t *cond);

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast(pthread_cond_t *cond);  //消弭一切线程的梗阻

(1)初始化.init()或pthread_cond_t cond=PTHREAD_COND_INITIALIER(前者为静态初始化,后者为静态初始化);属性置为NULL

(2)等待前提成立.pthread_wait,pthread_timewait.wait()释放锁,并梗阻等待前提变量为真,timewait()设置等待时分,仍未signal,前往ETIMEOUT(加锁包管只需一个线程wait)

(3)激活前提变量:pthread_cond_signal,pthread_cond_broadcast(激活一切等待线程)

(4)断根前提变量:destroy;无线程等待,不然前往EBUSY

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);

必然要在mutex的锁定区域内应用。

   若是要精确的应用pthread_mutex_lock与pthread_mutex_unlock,请参考

pthread_cleanup_push和pthread_cleanup_pop宏,它能够或许在线程被cancel的时辰精确的释放mutex!

   别的,posix1尺度说,pthread_cond_signal与pthread_cond_broadcast无需推敲挪用线程是不是是mutex的具有者,也就是说,能够在lock与unlock之外的区域挪用。若是我们对换用行动不关心,那末请在lock区域以外挪用吧。

声明:

   (1)pthread_cond_wait 主动解锁互斥量(犹如实行了pthread_unlock_mutex),并等待前提变量触发。这时分线程挂起,不占用CPU时分,直到前提变量被触发(变量为ture)。在挪用 pthread_cond_wait之前,应用法式必需加锁互斥量。pthread_cond_wait函数前往前,主动从头对互斥量加锁(犹如实行了pthread_lock_mutex)。

   (2)互斥量的解锁和在前提变量上挂起都是主动中止的。是以,在前提变量被触发前,若是一切的线程都要对互斥量加锁,这类机制可包管在线程加锁互斥量和进进等待前提变量时期,前提变量不被触发。前提变量要和互斥量相联络,以免呈现前提竞争——个线程豫备等待一个前提变量,当它在真正进进等待之前,另外一个线程刚好触发了该前提(前提知足旌旗灯号有可以在测试前提和挪用pthread_cond_wait函数(block)之间被收回,从而构成无量制的等待)。

(3)pthread_cond_timedwait 和 pthread_cond_wait 一样,主动解锁互斥量及等待前提变量,但它还限制了等待时分。若是在abstime指定的时分内cond未触发,互斥量mutex被从头加锁,且pthread_cond_timedwait前往缺点 ETIMEDOUT。abstime 参数指定一个尽对时分,时分原点与 time 和gettimeofday 不异:abstime = 0 暗示 1970年1月1日00:00:00 GMT。

(4)pthread_cond_destroy 烧毁一个前提变量,释放它具有的资本。进进 pthread_cond_destroy 之前,必需没有在该前提变量上等待的线程。

   (5)前提变量函数不是异步旌旗灯号安全的,不应当在旌旗灯号处置法式中中止挪用。出格要注重,若是在旌旗灯号处置法式中挪用 pthread_cond_signal 或pthread_cond_boardcast 函数,可以致使挪用线程死锁。

示例法式1

#include stdio.h #include pthread.h #include "stdlib.h"#include "unistd.h"pthread_mutex_t mutex;pthread_cond_t cond;void hander(void *arg) free(arg);  (void)pthread_mutex_unlock( mutex);void *thread1(void *arg) pthread_cleanup_push(hander, mutex);  while(1)  printf("thread1 is runningn");  pthread_mutex_lock( mutex);  pthread_cond_wait( cond, mutex);  printf("thread1 applied the conditionn");  pthread_mutex_unlock( mutex);  sleep(4);  pthread_cleanup_pop(0); void *thread2(void *arg) while(1)  printf("thread2 is runningn");  pthread_mutex_lock( mutex);  pthread_cond_wait( cond, mutex);  printf("thread2 applied the conditionn");  pthread_mutex_unlock( mutex);  sleep(1); int main() pthread_t thid1,thid2;  printf("condition variable study!n");  pthread_mutex_init( mutex,NULL);  pthread_cond_init( cond,NULL);  pthread_create( thid1,NULL,thread1,NULL);  pthread_create( thid2,NULL,thread2,NULL);  sleep(1);  pthread_cond_signal( cond);  }while(1);  sleep(20);  pthread_exit(0);  return 0;}

示例法式2:

#include pthread.h #include unistd.h #include "stdio.h"#include "stdlib.h"static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; struct node  int n_number;  struct node *n_next; } *head = NULL; /*[thread_func]*/ static void cleanup_handler(void *arg)  printf("Cleanup handler of second thread./n");  free(arg);  (void)pthread_mutex_unlock( mtx); static void *thread_func(void *arg)  struct node *p = NULL;  pthread_cleanup_push(cleanup_handler, p);  while (1)  //这个mutex首要是用来包管pthread_cond_wait的并发性 pthread_mutex_lock( mtx);  while (head == NULL)  //这个while要出格声明一下,单个pthread_cond_wait功用很圆满,为什么 //这里要有一个while (head == NULL)呢?由于pthread_cond_wait里的线  //程可以会被不测叫醒,若是这个时辰head != NULL,则不是我们想要的环境。  //这个时辰,应当让线程连续进进pthread_cond_wait  // pthread_cond_wait会先消弭之前的pthread_mutex_lock锁定的mtx,  //然后梗阻在等待对列里休眠,直到再次被叫醒(年夜大都环境下是等待的前提成立  //而被叫醒,叫醒后,该进程会先锁定先pthread_mutex_lock( mtx);,再读取资本  //用这个流程是比力明晰的/*block-- unlock-- wait() return-- lock*/ pthread_cond_wait( cond, mtx);  p = head;  head = head- n_next;  printf("Got %d from front of queue/n", p- n_number); free(p);  pthread_mutex_unlock( mtx); //临界区数据支配终了,释放互斥锁  pthread_cleanup_pop(0);  return 0; int main(void)  pthread_t tid;  int i;  struct node *p;  //子线程会一向等待资本,近似出产者和消费者,可是这里的消费者可所以多个消费者,而  //不但仅支撑浅显的单个消费者,这个模子固然俭朴,可是很壮大 pthread_create( tid, NULL, thread_func, NULL);  sleep(1);  for (i = 0; i i++)  p = (struct node*)malloc(sizeof(struct node));  p- n_number = i;  pthread_mutex_lock( mtx); //需求支配head这个临界资本,先加锁,  p- n_next = head;  head = p;  pthread_cond_signal( cond);  pthread_mutex_unlock( mtx); //解锁  sleep(1);  printf("thread 1 wanna end the line.So cancel thread 2./n");  //关于pthread_cancel,有一点额定的声明,它是从内部终止子线程,子线程会在比来的消除点,参加  //线程,而在我们的代码里,比来的消除点必定就是pthread_cond_wait()了。  pthread_cancel(tid);  pthread_join(tid, NULL);  printf("All done -- exiting/n");  return 0; }

3)旌旗灯号量

   犹如进程一样,线程也可以经由过程旌旗灯号量来完成通讯,固然是轻量级的。

   旌旗灯号量函数的名字都以 sem_ 打头。线程应用的根基旌旗灯号量函数有四个。

#include semaphore.h

int sem_init (sem_t *sem , int pshared, unsigned int value);

   这是对由sem指定的旌旗灯号量中止初始化,设置好它的同享选项(linux 只支撑为0,即暗示它是以后进程的局部旌旗灯号量),然后给它一个初始值VALUE。

两个原子支配函数:

int sem_wait(sem_t *sem);

int sem_post(sem_t *sem);

   这两个函数都要用一个由sem_init挪用初始化的旌旗灯号量对象的指针做参数。

sem_post:给旌旗灯号量的值加1;

sem_wait:给旌旗灯号量减1;对一个值为0的旌旗灯号量挪用sem_wait,这个函数将会等待直到有其它线程使它不再是0为止。

int sem_destroy(sem_t *sem);

   这个函数的感化是再我们用完旌旗灯号量后都它中止清算。归还自身据有的一切资本。

示例代码:


#include stdlib.h #include stdio.h #include unistd.h #include pthread.h #include semaphore.h #include errno.h #define return_if_fail(p) if((p) == 0){printf ("[%s]:func error!/n", __func__);return;} typedef struct _PrivInfo  sem_t s1;  sem_t s2;  time_t end_time; }PrivInfo; static void info_init (PrivInfo* thiz); static void info_destroy (PrivInfo* thiz); static void* pthread_func_1 (PrivInfo* thiz); static void* pthread_func_2 (PrivInfo* thiz); int main (int argc, char** argv)  pthread_t pt_1 = 0;  pthread_t pt_2 = 0;  int ret = 0;  PrivInfo* thiz = NULL;  thiz = (PrivInfo* )malloc (sizeof (PrivInfo));  if (thiz == NULL)  printf ("[%s]: Failed to malloc priv./n");  return -1;  info_init (thiz);  ret = pthread_create ( pt_1, NULL, (void*)pthread_func_1, thiz);  if (ret != 0)  perror ("pthread_1_create:");  ret = pthread_create ( pt_2, NULL, (void*)pthread_func_2, thiz);  if (ret != 0)  perror ("pthread_2_create:");  pthread_join (pt_1, NULL);  pthread_join (pt_2, NULL);  info_destroy (thiz);  return 0; static void info_init (PrivInfo* thiz)  return_if_fail (thiz != NULL);  thiz- end_time = time(NULL) + 10;  sem_init ( thiz- s1, 0, 1);  sem_init ( thiz- s2, 0, 0);  return; static void info_destroy (PrivInfo* thiz)  return_if_fail (thiz != NULL);  sem_destroy ( thiz-  sem_destroy ( thiz-  free (thiz);  thiz = NULL;  return; static void* pthread_func_1 (PrivInfo* thiz)  return_if_fail (thiz != NULL);  while (time(NULL) thiz- end_time)  sem_wait ( thiz-  printf ("pthread1: pthread1 get the lock./n");  sem_post ( thiz-  printf ("pthread1: pthread1 unlock/n");  sleep (1);  return; static void* pthread_func_2 (PrivInfo* thiz)  return_if_fail (thiz != NULL);  while (time (NULL) thiz- end_time)  sem_wait ( thiz-  printf ("pthread2: pthread2 get the unlock./n");  sem_post ( thiz-  printf ("pthread2: pthread2 unlock./n");  sleep (1);  return; }

通 过实行成果后,能够看出,会先实行线程二的函数,然后再实行线程一的函数。它们两就完成了同步。在上年夜学的时辰,固然对这些概念明白,可都没有理论过,所 以有时辰时分一久就会恍惚乃至健忘,到了任务若是还连结这么一种情况,那就太恐惧了。固然此刻里面的手艺在不竭的转变卦新,可是不管怎样变,其焦点手艺还 是依旧的,所以我们必需求打好自身的基本,再进修其他新的常识,那时辰再学新的常识也会觉得比力俭朴的。

上一篇:返回列表

拒绝套路 试听有礼

数据已加密保证您的信息安全