[c++] c语言并发编程——POSIX

版权声明:转载请注明出处 https://blog.csdn.net/weixin_40937100/article/details/88785247

先来看以下关于c语言的几个问题

2.1 void*

C语言中void * 为 “不确定类型指针”,void *可以用来声明指针。如:void * a;

1void *可以接受任何类型的赋值:

    void *a = NULL;
    int * b = NULL;
    a  =  b;//a是void * 型指针,任何类型的指针都可以直接赋值给它,无需进行强制类型转换
2void *可以赋值给任何类型的变量 但是需要进行强制转换:

    int * a = NULL ;
    void * b ;
    a  =int *)b;
(3)void* 在转换为其他数据类型时,赋值给void* 的类型 和目标类型必须保持一致。
   即void* 类型接受了int * 的赋值后 这个void * 不能转化为其他类型,必须转换为int *类型

2.2 pthread_t

它是POSIX中新线程的标识符,关于POSIX这一篇文章介绍了pthread_attr_t ,线程同步:互斥锁(量)与条件变量,线程取消。

2.3 pthread_create

函数pthread_create用来创建一个线程,它的原型为:

extern int pthread_create __P ((
pthread_t *__thread,
__const pthread_attr_t *__attr,
void (__start_routine) (void *),
void *__arg));
  第一个参数为指向线程标识符的指针
  第二个参数用来设置线程属性
  第三个参数是线程运行函数的起始地址
  最后一个参数是运行函数的参数。
  这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空指针,这样将生成默认属性的线程。对线程属性的设定和修改我们将在下一节阐述。当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL.前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。

2.4 pthread_join、pthread_exit

函数pthread_join用来等待一个线程的结束。函数原型为:

extern int pthread_join __P ((pthread_t __th, void **__thread_return));
第一个参数为被等待的线程标识符
第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。

这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。一个线程的结束有两种途径,一种是我们上面的例子,函数结束了,调用它的线程也就结束了。

另一种方式是通过函数pthread_exit来实现。它的函数原型为:

extern void pthread_exit __P ((void *__retval)) attribute ((noreturn));
唯一的参数是函数的返回代码

只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给 thread_return.最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。

互斥锁用来保证一段时间内只有一个线程在执行一段代码。我们继续往下看:

2.5 pthread_mutex_init

函数pthread_mutex_init用来生成一个互斥锁。NULL参数表明使用默认属性。如果需要声明特定属性的互斥锁,须调用函数 pthread_mutexattr_init.函数pthread_mutexattr_setpshared和函数 pthread_mutexattr_settype用来设置互斥锁属性。前一个函数设置属性pshared,它有两个取值, PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED.前者用来不同进程中的线程同步,后者用于同步本进程的不同线程。在上面的例子中,我们使用的是默认属性PTHREAD_PROCESS_ PRIVATE.后者用来设置互斥锁类型,可选的类型有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、 PTHREAD_MUTEX_RECURSIVE和PTHREAD _MUTEX_DEFAULT.它们分别定义了不同的上所、解锁机制,一般情况下,选用最后一个默认属性。

2.6 pthread_mutex_lock、pthread_mutex_unlock、pthread_delay_np

pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,均被上锁,即同一时间只能被一个线程调用执行。当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁。

上面的内容关于c语言和POSIX

下面的内容来自这篇文章,在前面先讲解了c++的核心基本内容,后面这个案例就是基于c和POSIX的,提出了对象线程的封装

源码如下:

#include<iostream>  
#include <pthread.h>  
using namespace std;  
  
class Thread  //虚基类Thread
{  
public:  
    Thread(string name = "Unknown"){}  
    virtual ~Thread(){}  
    
    void Start()  
    {  
       pthread_create(&m_ThreadID, NULL, ThreadFunc, this);  
    }
/* 第一个参数为指向线程标识符的指针
  第二个参数用来设置线程属性
  第三个参数是线程运行函数的起始地址,即为线程入口地址
  最后一个参数是运行函数的参数,即入口函数的参数
*/
  
    static void* ThreadFunc(void* pth)  
    {  
        Thread* p = static_cast<Thread*>(pth);//类型转换,得到类对象
        p->Run();
    }  
    virtual void Run() = 0;  //Thread类的启动函数为虚函数,说明Thread仅为一个基类,被继承
private:  
    pthread_t m_ThreadID;  	//私有变量是一个线程
};  
  
  
class Test:public Thread  //Test类继承自Thread
{  
public:  
    virtual void Run()  
    {  
        while(1)  
        {  
            cout<<"In Test::Run()"<<endl;  
        }  
    }  
};  
int main()  
{  
    Thread* thread1 = new Test();  
    thread1->Start();  
    sleep(1);  
}  

上面的代码用Thread这个类来实现线程的封装,用户自己要启用的线程类都要继承这个Thread类,在Thread类的Start函数里,调用了pthread_create创建了一个线程,并将ThreadFunc设置为线程函数,把线程的this指针传递给了这个函数,在这个线程函数里调用了
虚函数Run,这个Run函数最终会利用多态调用到用户线程类的Run函数,这就是上面代码的基本原理

2.7 对象线程封装

下面这种线程封装方式是用基于对象的封装方式,用到了boost库中的神器boost::function, boost::bind,这个神器原理就是帮定一个函数对象,函数对象可以包含参数,我们可以利用这个神器调用任意全局函数,甚至类的成员函数,源码如下:

#include<iostream>  
#include <pthread.h>  
#include <boost/function.hpp>  
#include <boost/bind.hpp>  
using namespace std;  
  
class Thread  
{  
    typedef boost::function<void(void)> ThreadFunctionCallBack;  
public:  
    Thread(ThreadFunctionCallBack cb, string name = "Unknow")  
        :m_cb(cb)
    {  
    }  
    ~Thread()  
    {
    }  
  
    void Start(void)  
    {  
        pthread_create(&m_ThreadID, NULL, ThreadFunction, this);  
    }  
  
    static void* ThreadFunction(void* obj)  
    {  
        Thread* thread = static_cast<Thread*>(obj);  
        thread->m_cb();  
    }  
  
private:  
    ThreadFunctionCallBack m_cb;  
    pthread_t m_ThreadID;  
};  
  
class Test  
{  
public:  
    void run(void)  
    {  
        cout<<"In test::run()"<<endl;  
    }  
};  
  
int main()  
{  
    Test t;  
    Thread thread1(boost::bind(&Test::run, &t));  
    thread1.Start();  
    usleep(100);  
}  

我们可以看到Test类不需要继承自Thread类,我们直接可以将boost::bind帮定的函数对象传递给Thread的构造函数,这里为了简单我们把this指针传递给了ThreadFunc,我们完全可以传递任何参数给ThreadFunc, 因为我们不需要使用多态,这就是基于对象的思想,比面向对象似乎更直接,使用起来更方便,更简单。

猜你喜欢

转载自blog.csdn.net/weixin_40937100/article/details/88785247