实现信号量(一) 开篇

        这系列文章是用管道、消息队列、条件变量来模拟实现信号量的功能。如果有bug,还望各位读者不吝指出。

        这里实现的信号量都是只能用于一个进程内多个线程进行通信的,并不能用于进程间的通信。这里的所有函数的返回值同POSIX标准中的线程那些函数一样,如果函数执行成功,返回0,否则返回错误编号。不会设置errno变量。

        测试的代码是《UNIX网络编程 卷2:进程间通信》中10.10和10.11节的结合,即多个生产者、多个消费者,多个缓冲区。为了测试方便,我还写了一个线程结构体。


        这里先贴出线程代码。

        Thread.hpp文件

#ifndef THREAD_HPP
#define THREAD_HPP


#include<pthread.h>
#include<semaphore.h>


typedef void* (threadFun)(void*);


typedef struct Thread_tag
{
    pthread_t tid;
    sem_t sem;
    pthread_mutex_t mutex;
    void* parameter; //线程执行函数的参数
    threadFun* realFun; //线程的执行函数
    int isRunning; //判断线程是否还在运行

    int valid; //用于判断这个结构体有没有被初始化,将赋值一个魔数
}Thread_t;


void* thread_temp_fun(void* arg);
int thread_init(Thread_t* thread);
int thread_create(Thread_t* thread, pthread_attr_t *attr, threadFun* fun );

//创建一个线程的时候并不会马上运行线程函数,而是要等到调用thread_start函数
//这类似于Java中的线程,需要显示调用start方法才会运行线程。
int thread_start(Thread_t* thread, void* arg);
int thread_join(Thread_t* thread, void **value);
int thread_cancel(Thread_t* thread);
int thread_destroy(Thread_t* thread);

#endif // THREAD_HPP


        Thread.cpp 文件

#include"Thread.hpp"
#include<errno.h>


#define THREAD_VALID 0xfabc

//临时函数。当一个调用thread_create创建一个线程时,线程将运行这个函数
//然后在这个函数里面停留,休眠。等待用户调用thread_start函数将线程唤醒
//然后线程进入到用户提供的线程运行函数。
//正是通过这种方式,造成一种假象:线程在调用thread_create后,并不会马上运行
//直到调用了thread_start函数后才会运行
void* thread_temp_fun(void* arg)
{
    void* status;
    Thread_t* thread = (Thread_t*)arg;
    sem_wait(&thread->sem); //等待另外一个线程调用thread_start唤醒
    thread->isRunning = 1;
    status = ((thread->realFun))(thread->parameter); //调用线程的执行函数
    thread->isRunning = 0;
    return status;
}


//这个函数不会线程安全的。
int thread_init(Thread_t* thread)
{
    int status;

    if( thread == NULL )
        return EINVAL;

    status = sem_init(&thread->sem, 0, 0);
    if( status != 0 )
        return status;

    status = pthread_mutex_init(&thread->mutex, NULL);
    if( status != 0 )
        return status;

    thread->isRunning = 0;
    thread->valid = THREAD_VALID; //赋值一个魔数
    return 0;
}


//make this process Atomically
int thread_create(Thread_t* thread, pthread_attr_t* attr, threadFun *fun )
{
    int status;

    if( thread == NULL || thread->valid != THREAD_VALID ||fun == NULL )
        return EINVAL;

    status = pthread_mutex_lock(&thread->mutex);
    if( status != 0 )
        return status;

    thread->realFun = fun;


    status = pthread_create(&thread->tid, attr, thread_temp_fun, thread);

	//ignore the error. if status == 0 and unlock return not 0.
	//we cann't return this message to user. it will confuse the user
	//the thread's creation is sucessful, but return error code	
    pthread_mutex_unlock(&thread->mutex);

	return status;
}



int thread_start(Thread_t* thread, void *arg)
{
    int status;

    if( thread == NULL || thread->valid != THREAD_VALID)
        return EINVAL;

    status = pthread_mutex_lock(&thread->mutex);
    if( status != 0 )
        return status;

    if( thread->isRunning )//now, this thread is running
    {
        pthread_mutex_unlock(&thread->mutex);
        return EBUSY;
    }

	//将线程运行时的参数传递给线程执行函数
    thread->parameter = arg;
    status = sem_post(&thread->sem);

    return status;
}


int thread_join(Thread_t* thread, void** value)
{
    if( thread == NULL || thread->valid != THREAD_VALID)
        return EINVAL;

    return pthread_join(thread->tid, value);
}


int thread_cancel(Thread_t* thread)
{
    if( thread == NULL || thread->valid != THREAD_VALID )
        return EINVAL;

    return pthread_cancel(thread->tid);
}


int thread_destroy(Thread_t* thread)
{
    int status1, status2;

    if( thread == NULL || thread->valid != THREAD_VALID)
        return EINVAL;


    status1 = pthread_mutex_lock(&thread->mutex);
    if( status1 != 0 )
        return status1;

    if( thread->isRunning )
    {
        pthread_mutex_unlock(&thread->mutex);
        return EBUSY;
    }

    status1 = pthread_mutex_unlock(&thread->mutex);
    if( status1 != 0 )
        return status1;

    status1 = pthread_mutex_destroy(&thread->mutex);
    status2 = sem_destroy(&thread->sem);

    if( status1 != 0 )
        return status1;

    return status2;
}






你可能感兴趣的:(线程,信号量)