线程的创建与中断
函数原型:
pthread_create(thread,attr,start_routine,arg)
pthread_exit(status)
pthread_attr_init(attr)
pthread_attr_destroy(attr)
PS:线程退出有几种方式:
线程从创建它的程序中返回
线程调用了pthread_exit函数
线程被另一个线程通过pthread_cancel所取消
整个进程终止
在main函数中使用pthread_exit退出时,其他线程仍然会继续进行。
/*******************线程的创建与终止*********************/
#include<pthread.h>
#include <stdio.h>
#define NUM_THREADS 5
void*PrintHello(void *threadid)
{
long tid;
tid = (long)threadid;
printf("Hello World! It's me,thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_tthreads[NUM_THREADS];
int rc;
long t;
for(t=0; t<NUM_THREADS; t++){
printf("In main: creatingthread %ld\n", t);
rc= pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return codefrom pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}
2. 向线程传递参数
传递一个基本的整型数据
long *taskids[NUM_THREADS];
for(t=0; t<NUM_THREADS;t++)
{
taskids[t] = (long *)malloc(sizeof(long));
*taskids[t] = t;
printf("Creatingthread %ld\n", t);
rc= pthread_create(&threads[t], NULL, PrintHello, (void *)taskids[t]);
...
}
2. 传递一个结构体
struct thread_data{
int thread_id;
int sum;
char *message;
};
struct thread_datathread_data_array[NUM_THREADS];
void *PrintHello(void*threadarg)
{
struct thread_data*my_data;
...
my_data = (structthread_data *) threadarg;
taskid =my_data->thread_id;
sum = my_data->sum;
hello_msg =my_data->message;
...
}
int main (int argc, char*argv[])
{
...
thread_data_array[t].thread_id= t;
thread_data_array[t].sum= sum;
thread_data_array[t].message= messages[t];
rc= pthread_create(&threads[t], NULL, PrintHello,
(void*) &thread_data_array[t]);
...
}
3. Join与Detach
函数原型:
pthread_join(threadid,status)
pthread_detach(threadid,status)
pthread_attr_setdetachstate(attr,detachstate)
pthread_attr_getdetachstate(attr,detachstate)
Linux中线程创建时默认是joinable的。
/*
This example demonstrates how to"wait" for thread completions by using the Pthread joinroutine. Since some implementations of Pthreads may not createthreads in a joinable state, the threads in this example areexplicitly created in a joinable state so that they can be joinedlater.
*/
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#defineNUM_THREADS 4
void*BusyWork(void *t)
{
inti;
longtid;
doubleresult=0.0;
tid= (long)t;
printf("Thread%ld starting...\n",tid);
for(i=0; i<1000000; i++)
{
result= result + sin(i) * tan(i);
}
printf("Thread%ld done. Result = %e\n",tid, result);
pthread_exit((void*)t);
}
intmain (int argc, char *argv[])
{
pthread_tthread[NUM_THREADS];
pthread_attr_tattr;
intrc;
longt;
void*status;
/*Initialize and set thread detached attribute */
pthread_attr_init(&attr);
/*显示设置线程为joinable*/
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
for(t=0;t<NUM_THREADS; t++) {
printf("Main:creating thread %ld\n", t);
rc= pthread_create(&thread[t], &attr, BusyWork, (void *)t);
if(rc) {
printf("ERROR;return code from pthread_create()
is%d\n", rc);
exit(-1);
}
}
/*Free attribute and wait for the other threads */
pthread_attr_destroy(&attr);
for(t=0;t<NUM_THREADS; t++) {
rc= pthread_join(thread[t], &status);
if(rc) {
printf("ERROR;return code from pthread_join()
is%d\n", rc);
exit(-1);
}
printf("Main:completed join with thread %ld having a status
of%ld\n",t,(long)status);
}
printf("Main:program completed. Exiting.\n");
pthread_exit(NULL);
}
4. 线程管理
4.1 栈管理
函数原型:
pthread_attr_getstacksize(attr, stacksize)
pthread_attr_setstacksize(attr, stacksize)
pthread_attr_getstackaddr(attr, stackaddr)
pthread_attr_setstackaddr(attr, stackaddr)
PS:线程默认的栈大小是不确定的,与具体的平台有关,所以考虑到可移植性,显示地设置栈大小是必要的。
/*
This exampledemonstrates how to query and set a thread's stack size.
*/
#include<pthread.h>
#include<stdio.h>
#defineNTHREADS 4
#defineN 1000
#defineMEGEXTRA 1000000
pthread_attr_tattr;
void*dowork(void *threadid)
{
doubleA[N][N];
inti,j;
longtid;
size_tmystacksize;
tid= (long)threadid;
pthread_attr_getstacksize(&attr, &mystacksize);
printf("Thread%ld: stack size = %li bytes \n", tid, mystacksize);
for(i=0; i<N; i++)
for(j=0; j<N; j++)
A[i][j]= ((i*j)/3.452) + (N-i);
pthread_exit(NULL);
}
intmain(int argc, char *argv[])
{
pthread_tthreads[NTHREADS];
size_tstacksize;
intrc;
longt;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &stacksize);
printf("Defaultstack size = %li\n", stacksize);
stacksize= sizeof(double)*N*N+MEGEXTRA;
printf("Amountof stack needed per thread = %li\n",stacksize);
pthread_attr_setstacksize(&attr, stacksize);
printf("Creatingthreads with stack size = %li bytes\n",stacksize);
for(t=0;t<NTHREADS; t++){
rc= pthread_create(&threads[t],&attr, dowork, (void *)t);
if(rc){
printf("ERROR;return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
printf("Created%ld threads.\n", t);
pthread_exit(NULL);
}
4.2 其他
函数原型:
pthread_self() //返回调用线程自己的线程ID号
pthread_equal(thread1,thread2) //比较两个线程是否为同一个线程
pthread_once(once_control, init_routine)
pthread_onceexecutes the init_routine exactlyonce in a process. The first call to this routine by any thread inthe process executes the given init_routine,without parameters. Any subsequent call will have no effect.
Theinit_routine routine is typically an initialization routine.
The once_controlparameter is a synchronization control structure that requiresinitialization prior to calling pthread_once.For example:
pthread_once_tonce_control = PTHREAD_ONCE_INIT;
5. 线程互斥
5.1 创建和销毁互斥量
Atypical sequence in the use of a mutex is as follows:
Create and initialize a mutexvariable
Several threads attempt to lockthe mutex
Only one succeeds and that threadowns the mutex
The owner thread performs some setof actions
The owner unlocks the mutex
Another thread acquires the mutexand repeats the process
Finally the mutex is destroyed
函数原型:
pthread_mutex_init(mutex,attr)
pthread_mutex_destroy(mutex)
pthread_mutexattr_init(attr)
pthread_mutexattr_destroy(attr)
信号量有两种初始化方式:
静态初始化:pthread_mutex_tmymutex = PTHREAD_MUTEX_INITIALIZER;
动态初始化:pthread_mutex_init()
5.2 互斥量的锁定与解锁
函数原型:
pthread_mutex_lock(mutex)
pthread_mutex_trylock(mutex)
pthread_mutex_unlock(mutex)
PS:phtread_mutext_Lock会试获取互斥量的锁,如果已经被占用,将会阻塞调用线程
pthread_mutext_trylock不同之处在于如果互斥量被占用,立即返回,而不会阻塞调用线程。
/*
This example programillustrates the use of mutex variables in a threads program thatperforms a dot product. The main data is made available to allthreads through a globally accessible structure. Each thread works ona different part of the data. The main thread waits for all thethreads to complete their computations, and then it prints theresulting sum.
*/
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
/*
Thefollowing structure contains the necessary information
toallow the function "dotprod" to access its input data and
placeits output into the structure.
*/
typedefstruct
{
double *a;
double *b;
double sum;
int veclen;
}DOTDATA;
/*Define globally accessible variables and a mutex */
#defineNUMTHRDS 4
#defineVECLEN 100
DOTDATAdotstr;
pthread_tcallThd[NUMTHRDS];
pthread_mutex_tmutexsum;
/*
Thefunction dotprod is activated when the thread is created.
Allinput to this routine is obtained from a structure
oftype DOTDATA and all output from this function is written into
thisstructure. The benefit of this approach is apparent for the
multi-threadedprogram: when a thread is created we pass a single
argumentto the activated function - typically this argument
is athread number. All the other information required by the
functionis accessed from the globally accessible structure.
*/
void*dotprod(void *arg)
{
/*Define and use local variables for convenience */
inti, start, end, len ;
longoffset;
doublemysum, *x, *y;
offset= (long)arg;
len= dotstr.veclen;
start= offset*len;
end = start + len;
x= dotstr.a;
y= dotstr.b;
/*
Performthe dot product and assign result
tothe appropriate variable in the structure.
*/
mysum= 0;
for(i=start; i<end ; i++)
{
mysum+= (x[i] * y[i]);
}
/*
Locka mutex prior to updating the value in the shared
structure,and unlock it upon updating.
*/
pthread_mutex_lock(&mutexsum);
dotstr.sum+= mysum;
pthread_mutex_unlock(&mutexsum);
pthread_exit((void*)0);
}
/*
Themain program creates threads which do all the work and then
printout result upon completion. Before creating the threads,
theinput data is created. Since all threads update a shared structure,
weneed a mutex for mutual exclusion. The main thread needs to wait for
allthreads to complete, it waits for each one of the threads. We specify
athread attribute value that allow the main thread to join with the
threadsit creates. Note also that we free up handles when they are
nolonger needed.
*/
intmain (int argc, char *argv[])
{
longi;
double*a, *b;
void*status;
pthread_attr_tattr;
/*Assign storage and initialize values */
a= (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));
b= (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));
for(i=0; i<VECLEN*NUMTHRDS; i++)
{
a[i]=1.0;
b[i]=a[i];
}
dotstr.veclen= VECLEN;
dotstr.a= a;
dotstr.b= b;
dotstr.sum=0;
pthread_mutex_init(&mutexsum,NULL);
/*Create threads to perform the dotproduct */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
for(i=0;i<NUMTHRDS; i++)
{
/*
Eachthread works on a different set of data.
Theoffset is specified by 'i'. The size of
thedata for each thread is indicated by VECLEN.
*/
pthread_create(&callThd[i],&attr, dotprod, (void *)i);
}
pthread_attr_destroy(&attr);
/*Wait on the other threads */
for(i=0;i<NUMTHRDS; i++)
{
pthread_join(callThd[i],&status);
}
/*After joining, print out the results and cleanup */
printf("Sum = %f \n", dotstr.sum);
free(a);
free(b);
pthread_mutex_destroy(&mutexsum);
pthread_exit(NULL);
}
6. 条件变量
6.1 创建和销毁条件变量
Conditionvariables provide yet another way for threads to synchronize. Whilemutexes implement synchronization by controlling thread access todata, condition variables allow threads to synchronize based uponthe actual value of data.
Withoutcondition variables, the programmer would need to have threadscontinually polling (possibly in a critical section), to check ifthe condition is met. This can be very resource consuming since thethread would be continuously busy in this activity. A conditionvariable is a way to achieve the same goal without polling.
A condition variable is always usedin conjunction with a mutex lock.
函数原型:
pthread_cond_init(condition,attr)
pthread_cond_destroy(condition)
pthread_condattr_init(attr)
pthread_condattr_destroy(attr)
PS:条件变量同互斥变量一样,也有两种初始化方式:
静态:pthread_cond_tmyconvar = PTHREAD_COND_INITIALIZER;
动态:利用pthread_cond_init()
attr对象主要指条件变量是否为:process-shared。
6.2 Waitingand Signaling on Condition Variables
函数原型:
pthread_cond_wait(condition,mutex)
pthread_cond_signal(condition)
pthread_cond_broadcast(condition)
Usage:
注意:
pthread_cond_wait()blocks the calling thread until the specified condition issignalled. This routine should be called while mutex islocked, and it will automatically release the mutex while it waits.After signal is received and thread is awakened, mutex willbe automatically locked for use by the thread. The programmer isthen responsible for unlocking mutex when the thread isfinished with it.
Thepthread_cond_signal() routine isused to signal (or wake up) another thread which is waiting on thecondition variable. It should be called after mutex islocked, and must unlock mutex in order forpthread_cond_wait() routine tocomplete.
Thepthread_cond_broadcast() routineshould be used instead of pthread_cond_signal()if more than one thread is in a blocking wait state.
It is a logical error to callpthread_cond_signal() beforecalling pthread_cond_wait().
Properlocking and unlocking of the associated mutex variable is essential when using these routines. For example:
Failing to lock the mutex beforecalling pthread_cond_wait() maycause it NOT to block.
Failing to unlock the mutex aftercalling pthread_cond_signal() maynot allow a matching pthread_cond_wait()routine to complete (it will remain blocked).
/*
This simple example codedemonstrates the use of several Pthread condition variable routines.The main routine creates three threads. Two of the threads performwork and update a "count" variable. The third thread waitsuntil the count variable reaches a specified value.
*/
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#defineNUM_THREADS 3
#defineTCOUNT 10
#defineCOUNT_LIMIT 12
int count = 0;
int thread_ids[3] = {0,1,2};
pthread_mutex_tcount_mutex;
pthread_cond_tcount_threshold_cv;
void*inc_count(void *t)
{
inti;
longmy_id = (long)t;
for(i=0; i<TCOUNT; i++) {
pthread_mutex_lock(&count_mutex);
count++;
/*
Checkthe value of count and signal waiting thread when condition is
reached. Note that this occurs while mutex is locked.
*/
if(count == COUNT_LIMIT) {
pthread_cond_signal(&count_threshold_cv);
printf("inc_count():thread %ld, count = %d Threshold reached.\n",
my_id,count);
}
printf("inc_count():thread %ld, count = %d, unlocking mutex\n",
my_id, count);
pthread_mutex_unlock(&count_mutex);
/*Do some "work" so threads can alternate on mutex lock */
sleep(1);
}
pthread_exit(NULL);
}
void*watch_count(void *t)
{
longmy_id = (long)t;
printf("Startingwatch_count(): thread %ld\n", my_id);
/*
Lockmutex and wait for signal. Note that the pthread_cond_wait
routinewill automatically and atomically unlock mutex while it waits.
Also,note that if COUNT_LIMIT is reached before this routine is run by
thewaiting thread, the loop will be skipped to prevent pthread_cond_wait
fromnever returning.
*/
pthread_mutex_lock(&count_mutex);
if(count<COUNT_LIMIT) {
pthread_cond_wait(&count_threshold_cv,&count_mutex);
printf("watch_count():thread %ld Condition signal received.\n", my_id);
count+= 125;
printf("watch_count():thread %ld count now = %d.\n", my_id, count);
}
pthread_mutex_unlock(&count_mutex);
pthread_exit(NULL);
}
intmain (int argc, char *argv[])
{
inti, rc;
longt1=1, t2=2, t3=3;
pthread_tthreads[3];
pthread_attr_tattr;
/*Initialize mutex and condition variable objects */
pthread_mutex_init(&count_mutex,NULL);
pthread_cond_init(&count_threshold_cv, NULL);
/*For portability, explicitly create threads in a joinable state */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
pthread_create(&threads[0],&attr, watch_count, (void *)t1);
pthread_create(&threads[1],&attr, inc_count, (void *)t2);
pthread_create(&threads[2],&attr, inc_count, (void *)t3);
/*Wait for all threads to complete */
for(i=0; i<NUM_THREADS; i++) {
pthread_join(threads[i],NULL);
}
printf("Main(): Waited on %d threads. Done.\n", NUM_THREADS);
/*Clean up and exit */
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
pthread_exit(NULL);
}