#include <pthread.h>
#include <stdio.h>
#define FAILURE 0
#define SUCCESS 1
#define UNS32 unsigned int
#define m_ERROR(format, args...) printf(format, ## args);//fflush(stdout);
static pthread_t g_pthread_wait;
static pthread_t g_pthread_signal;
static pthread_t g_pthread_mt;
pthread_mutex_t g_pthread_mutex;
pthread_cond_t g_pthread_cond;
UNS32 pthread_initialize_cond(void){
if ( (pthread_cond_init(&g_pthread_cond, NULL)) != 0 ) {
m_ERROR("/t!!! ERROR : pthread_cond_init !!!/n");
return FAILURE;
}
return SUCCESS;
}
UNS32 pthread_initialize_mutex(void){
if ( (pthread_mutex_init(&g_pthread_mutex, NULL)) != 0 ) {
m_ERROR("/t!!! ERROR : pthread_mutex_init !!!/n");
return FAILURE;
}
return SUCCESS;
}
/*
void pthread_cleanup(void *clean)
{
printf("pthread_cleanup!/n");
pthread_mutex_unlock(&g_pthread_mutex);
}
*/
void pthread_wait(void *args){
pthread_detach(pthread_self());
pthread_mutex_lock(&g_pthread_mutex);
//pthread_cleanup_push(pthread_cleanup, NULL);
printf("pthread_cond_wait_in /n");
pthread_cond_wait(&g_pthread_cond, &g_pthread_mutex);
printf("pthread_cond_wait_out /n");
//pthread_cleanup_pop(0);
pthread_mutex_unlock(&g_pthread_mutex);
pthread_exit(NULL);
}
void pthread_signal(void *args){
pthread_detach(pthread_self());
printf("pthread_signal_lock/n");
pthread_mutex_lock(&g_pthread_mutex);
printf("pthread_cond_signal_in/n");
pthread_cond_signal(&g_pthread_cond);
printf("pthread_cond_signal_out/n");
pthread_mutex_unlock(&g_pthread_mutex);
pthread_exit(NULL);
}
void pthread_mt(void *args) {
printf("pthread_cancel_in /n");
pthread_cancel(g_pthread_wait);
printf("pthread_cancel_out /n");
}
int main() {
pthread_initialize_cond();
pthread_initialize_mutex();
// int sh;
if (pthread_create(&g_pthread_wait, NULL, (void * (*)(void *)) pthread_wait, NULL) !=0) {
return FAILURE;
}
sleep(1);
// sh = pthread_mutex_trylock(&g_pthread_mutex);
// printf("%d/n", sh);
if (pthread_create(&g_pthread_mt , NULL, (void * (*)(void *)) pthread_mt, NULL) !=0) {
return FAILURE;
}
// sh = pthread_mutex_trylock(&g_pthread_mutex);
// printf("%d/n", sh);
sleep(1);
if (pthread_create(&g_pthread_signal , NULL, (void * (*)(void *)) pthread_signal, NULL) !=0) {
return FAILURE;
}
printf("while!/n");
while(1);
}
程序执行结果为:
pthread_cond_wait_in
pthread_cancel_in
pthread_cancel_out
while!
pthread_signal_lock
分析如下:
1,pthread_wait线程先打印pthread_cond_wait_in ,然后执行pthread_cond_wait等待g_pthread_cond条件的到来;
2,pthread_mt线程打印pthread_cancel_in 后将ID号为g_pthread_wait的线程pthread_wait杀死后,打印
pthread_cancel_out;
3,pthread_signal线程打印pthread_signal_lock之后,要进行加锁操作,也就阻塞在这里,不能继续执行了,
原因如下(待考证):因为步骤2,将pthread_wait线程杀死了,而pthread_wait线程当时的状态为pthread_cond_wait解锁等
待条件的到来,pthread_mt线程调用pthread_cancel杀掉pthread_wait时,会把pthread_cond_wait函数退出,而
pthread_cond_wait退出时,会把g_pthread_mutex加锁,那么步骤3中进行的加锁操作就阻塞了,不能继续执行。
解决方法1:
将棕色的代码pthread_mutex_lock(&g_pthread_mutex);换成非阻塞的加锁pthread_mutex_trylock(&g_pthread_mutex);
解决方法2:
将红色的注释掉的代码加进来,即加入线程清楚函数。
分析如下:
步骤1,2同上;但是线程pthread_wait加入了清除处理机制,所以当步2将线程pthread_wait杀掉时,导致线程
pthread_wait非正常退出,那么此时就会去执行pthread_cleanup_push(pthread_cleanup, NULL)函数所
指定的pthread_cleanup函数,打印pthread_cleanup!,并且将g_pthread_mutex锁解开(即:释放掉因为
pthread_wait线程被杀死时,pthread_cond_wait函数退出所占用的锁g_pthread_mutex);
3,pthread_signal线程打印pthread_signal_lock之后,要进行加锁操作,因为线程1被杀死的时候已经调用清除函数将锁打开
了,所以下面的代码可以顺利进行。
此时打印结果为:
pthread_cond_wait_in
pthread_cancel_in
pthread_cancel_out
pthread_cleanup!
while!
pthread_signal_lock
pthread_cond_signal_in
pthread_cond_signal_out
说明的是:
1,pthread_cleanup_push与pthread_cleanup_pop函数的使用位置要灵活运用,中间只需加入线程函数代码中的容易出
现异常退出的代码段即可,此配对函数常用来释放掉线程自己所占用的资源。
2,要学会利用紫色部分的pthread_mutex_trylock函数的返回值进行调试,来测试锁是否能被锁住:如果调用
pthread_mutex_trylock时互斥量处于未锁住状态,那么pthread_mutex_trylock将锁住互斥量,
不会出现阻塞并返回0,否则pthread_mutex_trylock就会失败,不能锁住互斥量,而返回EBUSY。
注意:pthread_cancel 的程序都是很“暴力的”。如果线程里面使用了内存分配,将会出现内存泄漏!!!