Coin163

首页 > Posix多线程

Posix多线程

相关标签: linux 多线程 posix cc++

2021腾讯云限时秒杀,爆款1核2G云服务器298元/3年!(领取2860元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1062

2021阿里云最低价产品入口+领取代金券(老用户3折起),
入口地址https://www.aliyun.com/minisite/goods

相关推荐:C++封装POSIX 线程库(四)使用封装的线程

C++封装POSIX 线程库(四)使用封装的线程 本文主要介绍如何使用 C++封装POSIX 线程库(一)互斥锁、C++封装POSIX 线程库(二)条件变量的封装和C++封装POSIX 线程库(三)线程的封装三文中介绍的POSIX Pthread的基本组件(互斥锁,条件变量和线程)C++封装的

子线程回调函数标准定义

threadfunction指针:void * (*ptr_thread_func)(void *)
threadcleannp指针:void (*ptr_thread_cleanup_func)(void *)

定义:
void cleanup(void *);

void * thread_func(void * argv)
{
    pthread_cleanup_push(cleanup, &mutex);    //cleanup_class宏
    
    pthread_mutex_lock(&mutex);    //加锁
    pthread_cond_wait(&cond, &mutex);    //挂起等待条件
    pthread_mutex_unlock(&mutex);    //解锁

    pthread_cleanup_pop(0);
}

void cleanup(void * arg)
{
    pthread_mutex_unlock(&mutex);    //防御性收尾工作,对互斥锁解锁,防止线程在等待中被取消


对互斥锁进行递归加锁

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

void test()
{
    pthread_mutex_t theMutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);

    pthread_mutex_init(&theMutex, &attr);
    pthread_mutexattr_destroy(&attr);

    pthread_mutex_lock(&theMutex);
    pthread_mutex_lock(&theMutex);

    pthread_mutex_unlock(&theMutex);
    pthread_mutex_unlock(&theMutex);
}

int main()
{
    printf("start!\n");

    test();

    return 0;
}
test函数中对互斥锁进行了两次以上的加锁操作,在Posix多线程编程编程中第二次的加锁操作造成了线程的死锁,而大多数情况下这并不合乎我们的意愿。
在test函数中需要对“互斥锁属性”的对象使用pthread_mutexattr_settype函数明确设置递归属性,如下程序所示:
void test()
{
    pthread_mutex_t theMutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);

    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);

    pthread_mutex_init(&theMutex, &attr);
    pthread_mutexattr_destroy(&attr);

    pthread_mutex_lock(&theMutex);
    pthread_mutex_lock(&theMutex);

    pthread_mutex_unlock(&theMutex);
    pthread_mutex_unlock(&theMutex);
}
在Posix多线程编程中,初始化互斥锁属性的时候尽量设置递归属性可以大大的降低死锁发生的可能性。

相关推荐:Linux C++的多线程编程

原文地址:http://www.cnblogs.com/youtherhome/archive/2013/03/17/2964195.html Linux C++的多线程编程 1. 引言   线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者。传统的Unix也支持线


信号配合线程信号掩码的使用

信号安装
struct sigaction actions;
memset(&actions, 0, sizeof(actions));

sigemptyset(&actions.sa_mask);    //清空信号集
actions.sa_flags = 0;    //只传递int的简单处理
actions.sa_handler = sighand;    //处理函数

rc = sigaction(SIGALRM, &actions, NULL);    //安装

处理函数定义
void sighand(int signo)
{
    pthread_t tid=pthread_self();
    printf("thread %lu in signal handler\n", tid);
    return;
}

主线程发出信号
rc = pthread_kill(threads[i], SIGALRM);
rc = pthread_kill(maskedthreads[i], SIGALRM);

子线程接到信号后阻塞并调用信号处理函数
void * threadfunc(void * parm)
{
    pthread_t tid = pthread_self();

    int rc;
    printf("thread %lu entered.\n", tid);

    rc = sleep(30);    //该子线程在这句等待中中断去调用信号处理函数

    printf("thread %lu did not get exp res! rc=%d.\n",\
           tid, rc);
    return NULL;
}

但是对于设置了信号掩码的子线程并不用中断去调用信号处理函数
sigset_t mask;
sigfillset(&mask);    //初始化信号集
rc = pthread_sigmask(SIG_BLOCK, &mask, NULL);    //设置信号掩码


线程的销毁和清理

为了预防子线程异常退出(或许它会被别的线程杀死,又或许它运行中发生了访问错误),我们需要在子线程函数中做如下步骤:
1 使用pthread_cleanup_push()/pthread_cleanup_pop()保护代码块
2 cleanuppush回调一个处理线程资源的函数,在函数中释放线程占用的资源
原因是线程在使用条件等待之前都会被要求对互斥区加锁,一旦线程在等待中异常退出,其它在等待相同互斥区的子线程会因为无法解锁而永远等待下去,于是一般会在cleanup回调函数中做一次解锁操作。
如函数标准定义所提到的那样。

但是,如果线程处于PTHREAD_CANCEL_ASYNCHRONOUS状态,上述代码段就有可能出错,因为退出动作有可能在pthread_cleanup_push()和pthread_mutex_lock()之间发生,或者在pthread_mutex_unlock()和pthread_cleanup_pop()之间发生,从而导致清理函数unlock一个并没有加锁的mutex变量,造成错误。

因此,在使用清理函数的时候,都应该暂时设置成PTHREAD_CANCEL_DEFERRED模式
int otype;
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &otype);    //设置成DEFERRED,这下就可以安心使用cleanup_class啦
pthread_cleanup_push(pthread_mutex_unlock, (void*)&mutex);
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);   //wait a cond...
pthread_mutex_unlock(&mutex);
pthread_cleanup_pop(1);
pthread_setcanceltype(otype, NULL);
return (void*)10086;

此外linux下还有另一种清理方法,就是使用pthread_cleanup_push_defer_np()/pthread_cleanup_pop_defer_np()扩展函数,不过这一对函数在别的操作系统是不被实现的,为可移植性考虑,还是老老实实的setcanceltype吧。

原文

子线程回调函数标准定义 threadfunction指针:void * (*ptr_thread_func)(void *) threadcleannp指针:void (*ptr_thread_cleanup_func)(void *) 定义: void cleanup(void *); void * thread_f

------分隔线----------------------------