细谈linux下的posix多线程编程

POSIX线程概述

定义:一个程序中的多个执行路线叫做线程,线程是一个进程内部的控制序列。所有的进程都至少有一个执行线程(初始线程)。初始线程随进程的创建而创建,其他线程则需要通过显式的函数调用来创建。

实现posix线程的主要函数。

①创建新线程

#include

int pthread_create(
         pthread_t * thread,                 //返回指向线程标识符的指针
         pthread_attr * attr,                 //设置线程属性
         void *(*func)(void*),               //新线程将启动的函数的地址
         void * arg );                            //传递给新线程启动函数的参数(注意类型的强制转换)

说明:函数执行成功返回0,失败返回错误码。执行成功后,新线程将从设定的函数处开始执行,原线程则继续执行。

 

②退出线程

#include

void pthread_exit(void * ret);

说明:终止调用此函数的线程,并返回一个指向某对象的指针(ret)。注意,不能返回指向局部变量的指针。注意:在主线程中调用pthread_exit,进程将等待所有线程结束后才终止。


③合并线程

#include

int pthread_join(pthread_t  thread, void **ret);

说明:等价于进程中用于收集子进程的wait()函数,thread 是要等待的线程(即通过pthread_creat函数返回的线程标识符),ret是一个二级指针,它指向一个指针,后者指向线程的返回值。函数执行成功时返回0,失败时返回错误码。pthread_join的功能是等待某线程结束,并收集其返回值。初始线程结束后(从main函数返回),整个进程即结束,导致进程内所有线程全部终止。在主线程中调用pthread_exit,进程将等待所有线程结束后才终止。

下面实现一个简单的多线程编程的例子。

#include #include #include #include #include char message[]="Hello World!"; void * thread_function(void * arg); int main() { pthread_t second_thread; void * thread_result; // create new thread if(pthread_create(&second_thread,NULL,thread_function,(void *)message)) { perror("Thread creation failed"); exit(EXIT_FAILURE); } printf("Waiting for thread to finish.../n"); // join the second_thread if(pthread_join(second_thread,&thread_result)) { perror("Thread joined failed"); exit(EXIT_FAILURE); } printf("Thread joined,it returned %s",(char*)thread_result); printf("Message is now %s/n",message); exit(EXIT_SUCCESS); } void * thread_function(void * arg) { printf("message is %s/n",(char*)arg); int i; for(i=0;i<3;++i) { printf("thread_function is running.(%d)/n",i); sleep(1); } strcpy(message,"Bye bye!"); pthread_exit("Thank you for CPU time./n"); }

 

线程同步:

       线程体现了程序执行的并发性(并行:并发、同时),多个线程并发执行,且同一进程内部的多个线程可以共享除局部变量之外的所有变量。用信号量同步线程用于线程同步,有四个处理函数:

#include

sem_t是用于同步的信号量
//初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int val); 

pshared:信号量类型,如为0,则为当前进程独享的信号量。
val:信号量的初始值。
//信号量减1
int sem_wait(sem_t *sem);
//信号量加1
int sem_post(sem_t *sem);
//销毁信号量
int sem_destory(sem_t *sem)

 

下面的例子验证了两个线程是并发执行的,其中一个线程用于读入用户输入的字符串,另一个线程用于统计字符串的长度。

#include #include #include #include #include #include #define BUFFER_SIZE 1024 sem_t bin_sem; char str_buf[BUFFER_SIZE]; void * thread_function(void * arg) { while(1) { sem_wait(&bin_sem); if(strncmp("end",str_buf,3)==0) { break; } printf("You input %d characters./n",strlen(str_buf)); } } int main() { pthread_t counter_thread; void * thread_result; // initialize semaphore if(sem_init(&bin_sem,0,0)) { perror("Semaphore initialization failed."); exit(EXIT_FAILURE); } // create letter counter thread if(pthread_create(&counter_thread,NULL,thread_function,NULL)) { perror("Thread creation failed."); exit(EXIT_FAILURE); } // inform user to input the charactors printf("Please input some text(Enter 'end' to finish):"); while(strncmp("end",str_buf,3)!=0) { scanf("%s",str_buf); sem_post(&bin_sem); } printf("/nWaiting for counter thread to finish.../n"); // join other threads if(pthread_join(counter_thread,&thread_result)) { perror("Thread join failed."); exit(EXIT_FAILURE); } printf("Thread joined./n"); // destroy the sem sem_destroy(&bin_sem); exit(EXIT_SUCCESS); return 0; }

 

线程互斥:

用互斥量同步线程互斥量允许程序员原子性的锁住某对象,使得每次只有一个线程可以访问它。

互斥量基本函数

#include
//初始化互斥量
int pthread_mutex_init(pthread_mutex * mutex,const pthread_mutexattr_t * mutexattr);
//互斥量加锁
int pthread_mutex_lock(pthread_mutex * mutex);
//互斥量解锁
int pthread_mutex_unlock(pthread_mutex * mutex);
//销毁互斥量
int pthread_mutex_destroy(pthread_mutex * mutex);

 

      程序需要仔细设计,避免死锁。下面的例子验证了两个线程是并发执行的,其中一个线程用于读入用户输入的字符串,另一个线程用于统计字符串的长度,线程在对共享区域(char str_buf[BUFFER_SIZE])操作时先对其加锁,操作完毕后解锁。

#include #include #include #include #include #include #define BUFFER_SIZE 1024 pthread_mutex_t str_mutex; char str_buf[BUFFER_SIZE]={0}; void * thread_function(void * arg) { while(strncmp("end",str_buf,3)!=0) { // the str_buf has data to read if(str_buf[0]!=0) { pthread_mutex_lock(&str_mutex); printf("You input %d characters./n",strlen(str_buf)); str_buf[0]='/0'; pthread_mutex_unlock(&str_mutex); } sleep(1); } } int main() { pthread_t counter_thread; void * thread_result; // initialize the str_mutex if(pthread_mutex_init(&str_mutex,NULL)) { perror("Mutex initialization failed."); exit(EXIT_FAILURE); } // create counter thread if(pthread_create(&counter_thread,NULL,thread_function,NULL)) { perror("Thread create failed."); exit(EXIT_FAILURE); } // inform the user to input some text printf("Please input some text(Enter 'end' to finish):"); while(strncmp("end",str_buf,3)!=0) { // the str_buf is empty if(str_buf[0]=='/0') { pthread_mutex_lock(&str_mutex); scanf("%s",str_buf); pthread_mutex_unlock(&str_mutex); } sleep(1); } printf("Waiting for counter thread to finish./n"); // join counter thread if(pthread_join(counter_thread,&thread_result)) { perror("Thread join failed."); exit(EXIT_FAILURE); } printf("Counter thread joined./n"); pthread_mutex_destroy(&str_mutex); return 0; }

 

线程属性:

创建线程时可以指定线程的属性,需要首先创建一个属性对象,然后用这个属性对象作为参数去创建线程。

#include

int pthread_attr_init(pthread_attr_t *attr);

属性举例

如果不需要新创建的线程向主函数返回参数,也不需要初始线程等待新创建的线程执行结束,此时可以指定新线程的属性为分离属性。

#include

int pthread_attr_setdetachstate(
              pthread_attr_t* attr                 //属性对象
              int detachstate  );                     //属性值
PTHREAD_CREATE_DETACHED:分离线程,无需(严格来说是不可以)使用pthread_join()函数合并。 
PTHREAD_CREATE_JOINABLE:允许其他线程合并此线程。

 

#include #include #include #include char message[]="Hello World."; int thread_finished=0; void * thread_function(void * arg) { printf("Thread_function is running.Argument was %s./n",(char*)message); sleep(4); printf("Second thread setting finished flag,and exiting now/n"); thread_finished=1; pthread_exit(NULL); } int main() { pthread_t second_thread; void * thread_result; pthread_attr_t thread_attr; // initialize the thread_attr if(pthread_attr_init(&thread_attr)) { perror("Attribute creation failed."); exit(EXIT_FAILURE); } // set detach attribute to the new thread if(pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED)) { perror("Setting detached attribute failed."); exit(EXIT_FAILURE); } // create new thread if(pthread_create(&second_thread,&thread_attr,thread_function,(void*)message)) { perror("Thread creation failed."); exit(EXIT_FAILURE); } // destroy the thread_attr pthread_attr_destroy(&thread_attr); while(!thread_finished) { printf("Waiting for thread to say it is finished.../n"); sleep(1); } printf("Second thread finished,bye!/n"); exit(EXIT_SUCCESS); }

 

线程取消:

线程可以终止另一个线程

#include

int pthread_cancel(pthread_t  thread);

thread:需要取消的线程标识符,由pthread_creat()返回。

 

线程需要设置是否允许被其他线程终止,即设置自己的取消状态

#include

int pthread_setcancelstate(int state, int *oldstate);

state: PTHREAD_CANCEL_ENABLE:允许自身被其他线程取消。  PTHREAD_CANCEL_DISABLE:不允许被取消。

oldstate:返回先前的取消状态。

 

线程还需要设置自己的取消类型

#include

int pthread_setcanceltype(int type, int *oldtype);

type:

PTHREAD_CANCEL_ASYNCHRONOUS:接收到取消请求后立即取消。

PTHREAD_CANCEL_DEFERRED:接到取消请求后,一直等待到线程执行了下述函数才取消——pthread_join,pthread_cond_wait,pthread_cond_timedwait,pthread_testcancel,sem_wait,sigwait。

#include #include #include #include void * thread_function(void * arg) { // set thread's cancel state if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL)) { perror("Set cancel state failed."); exit(EXIT_FAILURE); } // set thread's cancel type if(PTHREAD_CANCEL_DEFERRED,NULL) { perror("Set cancel type failed."); exit(EXIT_FAILURE); } printf("thread_function is running./n"); int i; for(i=0;i<10;++i) { printf("Thread is still running (%d).../n",i); sleep(1); } pthread_exit(NULL); } int main() { pthread_t second_thread; void * thread_result; // create new thread if(pthread_create(&second_thread,NULL,thread_function,NULL)) { perror("Thread creation failed."); exit(EXIT_FAILURE); } sleep(3); printf("Canceling second_thread.../n"); // cancel the second_thread if(pthread_cancel(second_thread)) { perror("Thread cancelation failed."); exit(EXIT_FAILURE); } printf("Waiting for thread to finish.../n"); // join the second_thread if(pthread_join(second_thread,&thread_result)) { perror("Thread join failed."); exit(EXIT_FAILURE); } return 0; }

你可能感兴趣的:(C/C++学习笔记,操作系统学记笔记,Linux学习笔记)