跨平台线程库——pThread
2016-05-03 17:05
337 查看
基本接口介绍:
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_timedwait同pthread_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 * sem, const 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.
2.
3.
http://www.cppblog.com/saha/articles/189802.html
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_timedwait同pthread_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 * sem, const 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
相关文章推荐
- nginx 的location 的用法
- static函数和普通函数的区别
- 作业七 用户体验设计案例分析
- Fragment与Activity的生命周期
- 设计模式——单例模式
- Qt多线程笔记 (2)
- iOS Status bar 颜色改为白色
- MVC设计模式与多层架构
- ZOJ 3822 Domination(概率DP)
- android raw与assets区别
- Oracle 游标使用全解
- 【krpano】krpano xml资源解密(破解)软件说明与下载(v1.2)
- Kinds of Fuwas
- Linux下Java获取本机IP地址
- iOS开发实战:如何将非ARC的项目转换成ARC项目
- 文章标题
- 《构建之法》读第六、第七章有感
- Microsoft Sync Framework 2.1 可再发行程序包 Microsoft Sync Framework 1.0 SP1 - 中文(简体)
- 01.javascript中字符串常用操作总结、JS字符串操作大全
- 在windows上部署使用Redis