您的位置:首页 > 其它

实现信号量(一) 开篇

2014-01-05 16:02 211 查看
这系列文章是用管道、消息队列、条件变量来模拟实现信号量的功能。如果有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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: