专题 9 线程

  1. 线程的创建与中断

函数原型:

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. 向线程传递参数

  1. 传递一个基本的整型数据

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. JoinDetach

函数原型:

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. 线程互斥

  • 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

5.1 创建和销毁互斥量

函数原型:

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. 条件变量

  • 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.

6.1 创建和销毁条件变量

函数原型:

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);


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值