跨平台线程库——pThread

基本接口介绍:
1.   pthread_create 

  #include <pthread.h>

   int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg);

   创建一个由调用线程控制的新的线程并发运行。新的线程使用 start_routine作为实现体,并以 arg作为第一个参数。
   新的线程可以通过调用pthread_exit显式结束,或者通过 start_routine return来隐式结束。其中后者等价于调用pthread_exit并以 start_routine 的返回值作为退出码。
      新线程的初始信号状态继承自他的创建线程,并且没有挂起的信号。pthread-win32暂时未实现信号量。
       attr参数指明新线程的属性,如果attr=NULL,则使用默认属性:新线程是joinable(not detached),和默认的调度策略(非实时)
      返回值:如果成功,新线程的指针会被存储到 thread的参数中,并返回0。如果错误则一个非0的错误码返回。
      如果返回EAGAIN,没有足够的系统资源创建一个线程,或者已经存在大于 PTHREAD_THREADS_MAX个活跃线程。

2. pthread_exit
   #include <pthread.h>
   void pthread_exit(void *retval);
   
pthread_exit结束调用线程的执行.所有通过pthread_cleanup_push设置的清除句柄将会被反序执行(后进先出)。
 所以key值非空的线程特定数据Finalization functions被调用(参见pthread_key_create)。
  最后调用线程被终止。
  retval是这个线程结束的返回值,可以通过在别的线程中调用pthread_join来获取这个值。
   没有返回 值。

3. pthread_join 
   #include <pthread.h>
   int pthread_join(pthread_t th, void **thread_return);    

   挂载一个在执行的线程直到该线程通过调用pthread_exit或者cancelled结束。(阻塞的方式等待指定的现成结束,释放线程资源)
   如果thread_return不为空,则线程th的返回值会保存到thread_return所指的区域。
   th的返回值是它给pthread_exit的参数,或者是pthread_canceled 如果是被cancelled的。
   被依附的线程th必须是joinable状态。一定不能是detached通过使用pthread_detach或者pthread_create中使用pthread_create_detached属性。
   当一个joinable线程结束时,他的资源(线程描述符和堆栈)不会被释放直到另一个线程对它执行pthread_join操作。
   如果成功,返回值存储在thread_return中,并返回0,否则返回错误码:
   ESRCH:找不到指定线程
   EINVAL:线程th是detached或者已经存在另一个线程在等待线程th结束
   EDEADLK:th的参数引用它自己(即线程不能join自身)

4.pthread_cancel   

   #include <pthread.h>
  int pthread_cancel(pthread_t thread);
  int pthread_setcancelstate(int state, int *oldstate);
  int pthread_setcanceltype(int type, int *oldtype);
  void pthread_testcancel(void);

   Cancellation是一种一个线程可以结束另一个线程执行的机制。更确切的说,一个线程可以发生Cancellation请求给另一个线程。
   根据线程的设置,收到请求的线程可以忽视这个请求,立即执行这个请求或者延迟到一个cancellation点执行。
   当一个线程执行Cancellation请求,相当于在那个点执行pthread_exit操作退出:所有cleanup句柄被反向调用,所有析构函数被调用结束线程并返回pthread_canceled.


5.pthread_cond   
   #include <pthread.h>
   pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
   int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
   int pthread_cond_signal(pthread_cond_t *cond);
   int pthread_cond_broadcast(pthread_cond_t *cond);
   int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
   int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
   int pthread_cond_destroy(pthread_cond_t *cond);

   
pthread_cond_init初始化条件变量,通过cond_attr,如果cond_attr是null则使用默认属性。也可以通过常量PTHREAD_COND_INITIALIZER静态初始化。
    pthread_cond_signal激活一个正在等待条件变量cond的线程。如果没有线程在等待则什么也不会发生,如果有多个线程在等待,则只能激活一个线程,带未指定是哪个线程(根据操作系统自己的调度策略选择)。
    pthread_cond_broadcast激活所有在等待条件变量cond的线程。
    pthread_cond_wait自动解锁mutex(pthread_unlock_mutex)等待条件变量cond发送。线程的执行被挂起不消耗cpu时间直到cond发送。在wait的入口mutex必须被锁住。
   在重新回到线程前, pthread_cond_wait会重新获得mutex(pthread_lock_mutex).解锁mutex和挂起是自动进行的。因此,如果所有线程在发送cond前都申请mutex的话,
   这种wait的内部实现机制能够保证在线程锁住mutex和线程wait之间不会有cond发送操作发送。
    pthread_cond_timedwaitpthread_cond_wait,只是多了个超时设置,如果超时,则重新获取mutex并且返回 ETIMEDOUT,时间为绝对时间。
    pthread_cond_destroy销毁一个条件变量。必须没有线程在wait该条件变量。
   condition函数是异步信号不安全的,容易产生死锁,必须自己控制调用流程避免死锁。

6.semaphore
 #include <semaphore.h>
 int sem_init(sem_t * sem , int  pshared , unsigned int  value );
 int sem_wait(sem_t *  sem );
 int sem_timedwait(sem_t *  semconst struct timespec * abstime );
 int sem_trywait(sem_t *  sem );
 int sem_post(sem_t *  sem );
 int sem_post_multiple(sem_t *  sem,  int  number );
 int sem_getvalue(sem_t *  sem , int *  sval );
 int sem_destroy(sem_t *  sem );

 sem_init:
初始化信号量,pshared表示该信号量是否只属于当前进程(pshared==0),如果pshared不为0则表示可以在进程间共享。value表示该信号量的初始值。
   sem_wait:如果信号量的值大于0,则自动减1并立即返回。否则线程挂起直到sem_post或sem_post_multiple增加信号量的值。
   sem_timedwait:同 sem_wait,只是多了个超时设置,如果超时,首先将全局变量errno设为ETIMEDOUT,然后返回-1.
   sem_trywait:如果信号量的值大于0,将信号量减1并立即返回,否则将全局变量errno设为ETIMEDOUT,然后返回-1。 sem_trywait不会阻塞。
   sem_post:释放一个正在等待该信号量的线程,或者将该信号量+1.
   sem_post_multiple:释放多个正在等待的线程。如果当前等待的线程数n小于number,则释放n个线程,并且该信号量的值增加(number - n).
   sem_get_value:返回信号量的值。在pthread-win32实现中,正值表示当前信号量的值,负值的绝对值表示当前正在等待该信号量的线程数。虽然在POSIX不需要这么表示,但是也是同样含义。


  信号量(sem)与条件变量(cond)的主要差别在于,条件变量等待必须在发送之前,否则容易出现死锁,而信号量等待可以在发送之后执行。一句话概括信号量对于操作的时序没有要求。


几个测试程序:
1.

#include <QCoreApplication>
#include <iostream>
#include "pthread.h"

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *Func1(void *);
void *Func2(void *);

int i = 1;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

#ifdef WIN32
#ifdef PTW32_STATIC_LIB
    pthread_win32_process_attach_np();
    pthread_win32_thread_attach_np();
#endif
#endif

    pthread_t thread1;
    pthread_t thread2;

    pthread_create(&thread1,NULL,Func1,(void*)NULL);
    pthread_create(&thread2,NULL,Func2,(void*)NULL);
    pthread_join(thread2,NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

#ifdef WIN32
#ifdef PTW32_STATIC_LIB
    pthread_win32_process_detach_np();
    pthread_win32_thread_detach_np();
#endif
#endif

    system("Pause");

    return a.exec();
}

void *Func1(void *junk)
{
    for(i = 1;i <= 9;i++)
    {
        if(i%3==0)
        {
            pthread_mutex_lock(&mutex);
            pthread_cond_signal(&cond);
            pthread_mutex_unlock(&mutex);
        }

        else
        {
            std::cout << "thread1: " << i << std::endl;
        }
    }
    return NULL;
}


void *Func2(void *junk)
{
    while(i<9)
    {
        if(i%3!=0)
        {
            pthread_mutex_lock(&mutex);
            pthread_cond_wait(&cond,&mutex);
            pthread_mutex_unlock(&mutex);
        }
        else
        {
            std::cout << "thread2: " << i << std::endl;
        }
    }
    return NULL;
}


 
 
2.
#include <stdio.h>
#include <Windows.h>
#include "pthread.h"
#include <ctype.h>

typedef struct arg_set
{
    char *fname;
    int count;
    int tid;
}ARG_SET;

bool bWait = false;
ARG_SET *mailbox = NULL;
pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t read_cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t write_cond = PTHREAD_COND_INITIALIZER;


void main(int ac, char *av[])
{
    pthread_win32_process_attach_np();
    pthread_win32_thread_attach_np();

    pthread_t t1, t2, t3;
    ARG_SET args1, args2, args3;
    void *count_words(void *);
    int reports_in = 0;
    int total_words = 0;

    if (4 != ac)
    {
        printf("usage: %s file1 file2 file3\n", av[0]);
        return;
    }
    
    args1.fname = av[1];
    args1.count = 0;
    args1.tid = 1;
    pthread_create(&t1, NULL, count_words, (void *)&args1);

    args2.fname = av[2];
    args2.count = 0;
    args2.tid = 2;
    pthread_create(&t2, NULL, count_words, (void *)&args2);

    args3.fname = av[3];
    args3.count = 0;
    args3.tid = 3;
    pthread_create(&t3, NULL, count_words, (void *)&args3);

    while(reports_in < 3)
    {
        printf("MAIN: waiting for flag to go up\n");
        pthread_mutex_lock(&read_lock);
        bWait = true;
        pthread_cond_wait(&read_cond, &read_lock);
        bWait = false;
        pthread_mutex_unlock(&read_lock);
        printf("MAIN: wow! flag was raised, I have the lock\n");

        printf("MAIN: %7d: %s\n", mailbox->count, mailbox->fname);
        total_words += mailbox->count;

        Sleep(10);

        printf("MAIN: Ok, I've read the thread %d mail\n", mailbox->tid);
        
        pthread_mutex_lock(&write_lock);
        pthread_cond_signal(&write_cond);
        pthread_mutex_unlock(&write_lock);
        printf("MAIN: raising write flag\n");

        reports_in++;
    }
    printf("%7d: total words\n", total_words);

    pthread_mutex_destroy(&read_lock);
    pthread_mutex_destroy(&write_lock);
    pthread_cond_destroy(&read_cond);
    pthread_cond_destroy(&write_cond);

    pthread_win32_thread_detach_np();
    pthread_win32_process_detach_np();

    system("pause");
}

void *count_words(void *a)
{
    ARG_SET *args = (ARG_SET*)a;
    FILE *fp;
    int c, prevc = '\0';

    if (NULL != (fp = fopen(args->fname, "r")))
    {
        while((c = getc(fp)) != EOF)
        {
            if (!isalnum(c) && isalnum(prevc))
            {
                args->count++;
            }
            prevc = c;
        }
        fclose(fp);
    }
    else
    {
        perror(args->fname);
    }

    printf("COUNT %d: waiting to get lock\n", args->tid);    
    
    
    pthread_mutex_lock(&write_lock);  
    if (NULL != mailbox)
    {
        printf("COUNT %d: oops..mailbox not empty. wait for signal\n", args->tid);
        pthread_cond_wait(&write_cond, &write_lock);
    }

    printf("COUNT %d: OK, I can write mail\n", args->tid);
    mailbox = args;  

    
    while (!bWait)
    {
        Sleep(1);        
    }
    pthread_mutex_lock(&read_lock); 
    pthread_cond_signal(&read_cond);    /* raise the flag */
    pthread_mutex_unlock(&read_lock); 

    printf("COUNT %d: raising read flag\n", args->tid);


    pthread_mutex_unlock(&write_lock);    /* release the mailbox */
    printf("COUNT %d: unlocking box\n", args->tid);    

    return NULL;
}

3.

#include <stdio.h>
#include <Windows.h>
#include "pthread.h"
#include "semaphore.h"
#include <ctype.h>

typedef struct arg_set
{
    char *fname;
    int count;
    int tid;
}ARG_SET;

ARG_SET *mailbox = NULL;
static sem_t sem_write;
static sem_t sem_read;


void main(int ac, char *av[])
{
    pthread_win32_process_attach_np();
    pthread_win32_thread_attach_np();

    pthread_t t1, t2, t3;
    ARG_SET args1, args2, args3;
    void *count_words(void *);
    int reports_in = 0;
    int total_words = 0;

    if (4 != ac)
    {
        printf("usage: %s file1 file2 file3\n", av[0]);
        return;
    }

    if (-1 == sem_init(&sem_read, 0 , 1)
        || -1 == sem_init(&sem_write, 0, 0))
    {
        return;
    }

    args1.fname = av[1];
    args1.count = 0;
    args1.tid = 1;
    pthread_create(&t1, NULL, count_words, (void *) &args1);
    
    args2.fname = av[2];
    args2.count = 0;
    args2.tid = 2;
    pthread_create(&t2, NULL, count_words, (void *) &args2);
    
    args3.fname = av[3];
    args3.count = 0;
    args3.tid = 3;
    pthread_create(&t3, NULL, count_words, (void *) &args3);


    while(reports_in < 3)
    {
        printf("MAIN: waiting for sub thread write\n");
        sem_wait(&sem_write);

        printf("MAIN: %7d: %s\n", mailbox->count, mailbox->fname);
        total_words += mailbox->count;
        if ( mailbox == &args1) 
            pthread_join(t1,NULL);
        if ( mailbox == &args2) 
            pthread_join(t2,NULL);
        if ( mailbox == &args3) 
            pthread_join(t3,NULL);
        
        mailbox = NULL;
        printf("MAIN: Ok,I have read the mail\n");
        sem_post(&sem_read);  
        reports_in++;
    }
   

    printf("%7d: total words\n", total_words);
    sem_destroy(&sem_read);
    sem_destroy(&sem_write);

    pthread_win32_thread_detach_np();
    pthread_win32_process_detach_np();

    system("pause");
}


void *count_words(void *a)
{
    struct arg_set *args = (arg_set *)a;    /* cast arg back to correct type */
    FILE *fp;
    int  c, prevc = '\0';
     
    if ( (fp = fopen(args->fname, "r")) != NULL )
    {
         while( ( c = getc(fp)) != EOF )
         {
               if ( !isalnum(c) && isalnum(prevc) )
               {
                    args->count++;
               }
               prevc = c;
         }
         fclose(fp);
     } else 
          perror(args->fname);
     printf("COUNT %d: waiting for main thread read the mail\n", args->tid);
     sem_wait(&sem_read);
     printf("COUNT %d:OK,I can write mail\n", args->tid);
     mailbox = args;            /* put ptr to our args there */
     printf("COUNT %d: Finished writting\n", args->tid);
     sem_post(&sem_write);
     return NULL;
}

http://www.cppblog.com/saha/articles/189802.html
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值