Unix高级环境编程系列笔记(2)

发表于:2013-11-18来源:IT博客大学习作者:nebula点击数: 标签:Unix
struct foo *fp; err = pthread_create(tid1, NULL, thr_fn1, NULL); if (err != 0) err_quit(can\t create thread 1: %s\\n, strerror(err)); err = pthread_join(tid1, (void *)fp); if (err != 0) err_quit(can\t

  struct foo *fp;

  err = pthread_create(&tid1, NULL, thr_fn1, NULL);

  if (err != 0)

  err_quit("can\'t create thread 1: %s\\n", strerror(err));

  err = pthread_join(tid1, (void *)&fp);

  if (err != 0)

  err_quit("can\'t join with thread 1: %s\\n", strerror(err));

  sleep(1);

  printf("parent starting second thread\\n");

  err = pthread_create(&tid2, NULL, thr_fn2, NULL);

  if (err != 0)

  err_quit("can\'t create thread 2: %s\\n", strerror(err));

  sleep(1);

  printfoo("parent:\\n", fp);

  exit(0);

  }

  注意,pthread_create 和 pthread_exit函数的无类型指针可以传递复杂的结构信息,但这个结构所使用的内存在调用者完成后必须仍然有效(分配在堆上或者是静态变量),否则就会出现使用无效的错误。这段代码中thr_fn1函数中变量foo分配在栈上,但该线程退出后,主线程通过pthread_join获取foo的地址并进行操作(调用printfoo函数时)就会出现错误,因为此时thr_fn1已经退出它的栈已经被销毁。

  5.如何通过一个线程让另外一个线程退出?

  调用pthread_cancel函数将导致tid所指向的线程终止运行。但是,一个线程可以选择忽略其它线程控制该线程何时退出。注意,该函数并不等待线程终止,它仅仅提出要求。

  #include

  int pthread_cancel(pthread_t tid);

  Returns: 0 if OK, error number on failure

  6.如何实现线程退出时的清理动作?

  线程可以建立多个清理处理程序,这些程序记录在栈中,也就是说他们的执行顺序与注册顺序想法。使用如下函数注册清理函数:

  void pthread_cleanup_push(void (*rtn)(void *), void *arg);

  void pthread_cleanup_pop(int execute);

  rtn将被调用,并传以arg参数,引起该函数调用的情况如下:

  o 调用pthread_exit

  o 对于退出请求的反应

  o 以非0参数调用pthread_cleanup_push

  如果pthread_cleanup_pop的参数非0则仅仅移除该处理函数而不执行。

  如果函数已经处于分离状态,则当它退出时线程底层的存储资源会被立即回收。处于分离状态的线程,如果调用pthread_join来等待其退出将会出现错误。

  通过下列函数可以让进程处于分离状态:

  #include

  int pthread_detach(pthread_t tid);

  Returns: 0 if OK, error number on failure

  7.Unix系统如何实现线程之间的同步?

  使用pthreads mutual-exclusion interfaces。引入了mutex,用pthread_mutex_t类型来表示。在使用这个变量之前,我们首先要将其初始化,或者赋值为 PTHREAD_MUTEX_INITIALIZER(仅仅用于静态分配的mutexs),或者调用pthread_mutex_init。如果我们动态的为mutex分配空间(例如通过调用malloc),我们需要在调用free释放内存之前调用pthread_mutex_destroy。

  函数定义如下:

以下是代码片段:
#include 
int pthread_mutex_init(pthread_mutex_t *restrict mutex,  const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
Both return: 0 if OK, error number on failure

  初始化mutex时参数attr用来指定mutex的属性,要使用默认值将它设置为NULL。

  使用如下函数对mutex进行加锁或解锁:

  int pthread_mutex_lock(pthread_mutex_t *mutex);

  int pthread_mutex_trylock(pthread_mutex_t *mutex);

  int pthread_mutex_unlock(pthread_mutex_t *mutex);

  All return: 0 if OK, error number on failure

  注意当mutex已经被加锁则 pthread_mutex_lock会阻塞。如果一个线程无法忍受阻塞,可以调用pthread_mutex_trylock来加锁,加锁失败则立即返回EBUSY。

  8.什么情况会发生线程死锁,如何避免死锁?

  如果一个线程对mutex加两次锁则显然会导致死锁。但实际上死锁的情况要复杂的多:when we use more than one mutex in our programs, a deadlock can occur if we allow one thread to hold a mutex and block while trying to lock a second mutex at the same time that another thread holding the second mutex tries to lock the first mutex. Neither thread can proceed, because each needs a resource that is held by the other, so we have a deadlock.

  死锁可以通过控制加锁的顺序来避免。有两个mutex A和B,如果所有的线程总是先对A加锁再对B加锁就不会产生死锁。但实际应用中可能很难保证这种顺序加锁的方式,这种情况下,可以使用pthread_mutex_trylock来避免死锁的发生。

  9.读写锁的使用方法。

  读写锁的初始化与销毁:

以下是代码片段:
#include 
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
Both return: 0 if OK, error number on failure
对于读写锁的初始化与销毁独占锁类似。

原文转自:http://blogread.cn/it/article/3344