apue笔记--第11章 线程

比较线程ID:

#include <pthread.h>
int pthread_equal(pthread_t tid1,pthread_t tid2)

获取自身线程ID

#include <pthread.h>
pthread_t pthread_self(void);


打印线程ID code 11_2 

/*
    打印线程ID

*/

#include "apue.h"
#include <pthread.h>

pthread_t ntid;

void pr_tids(const char*s){

    pid_t pid;
    pthread_t tid;
    pid = getpid();
    tid = pthread_self();
    printf("%s pid %lu tid %lu (0x%1x)\n",s,(unsigned long) pid,(unsigned long)tid,(unsigned long)tid);

    
}
void *thr_fn(void *arg){
    pr_tids("new thread: ");
    return ((void*)0);
}

int main(){

    int err;
    err = pthread_create(&ntid,NULL,thr_fn,NULL);
    if(err!=0)
        printf("cannot create thread\n");
    
    pr_tids("main thread: ");
    sleep(1);
    exit(0);
}

线程退出 pthrad_exit() code 11_3

#include "apue.h"
#include <pthread.h>

/*
    线程终止方法:
    1.线程从启动例程中返回,返回值是线程的退出码
    2.线程可以被同一进程的其他线程取消
    3.线程调用pthread_exit

    当一个线程通过调用pthread_exit退出或者简单的从例程中返回是,
    进程中的其他线程可以通过pthread_join()获得该线程的退出状态

output:

kali@kali:~/Desktop/Linux Study/Hellos/Chapter11$ ./PthreadExit_11_3
thread 1 returning
thread 2 exiting
 thread 1 exit code 1
thread 2 exit code 2
*/
void *thr_fn1(void *arg){
    printf("thread 1 returning\n");
    return ((void*)1);
}

void *thr_fn2(void *arg){
    printf("thread 2 exiting\n");
    pthread_exit((void*)2);
}
int main(void){

    int err;
    pthread_t tid1,tid2;
    void *tret;
    err = pthread_create(&tid1,NULL,thr_fn1,NULL);
    if(err!=0){
        printf("cannot create thread 1,err = %d",err);
    }
     err = pthread_create(&tid2,NULL,thr_fn2,NULL);
    if(err!=0){
        printf("cannot create thread 2,err = %d",err);
    }
    err = pthread_join(tid1,&tret);
    if(err!=0){
        printf("pthread_join,err = %d",err);
    }
    printf(" thread 1 exit code %ld\n",(long)tret);
    err = pthread_join(tid2,&tret);
    if(err!=0){
        printf("pthread_join,err = %d",err);
    }
    printf("thread 2 exit code %ld\n",(long)tret);
    exit(0);
}

 pthread_exit 参数的不正确使用 code 11_4

/*
    pthread_exit 参数的不正确使用

output:

kali@kali:~/Desktop/Linux Study/Hellos/Chapter11$ ./PthreadExit_11_4
thread 1
structure at 0x7ed25ee0
 foo.a = 1
 foo.b = 2
 foo.c = 3
 foo.d = 4
parent starting thread 2thread 2: ID is 140700961367808
parent:
structure at 0x7ed25ee0
 foo.a = 1
 foo.b = 0
 foo.c = 0
 foo.d = 0

*/
#include "apue.h"
#include <pthread.h>


struct foo{
    int a,b,c,d;
};

void pr_foo(const char* s,const struct foo *fp){

    printf("%s",s);
    printf("structure at 0x%1x\n",(unsigned long)fp);
    printf(" foo.a = %d\n",fp->a);
    printf(" foo.b = %d\n",fp->b);
    printf(" foo.c = %d\n",fp->c);
    printf(" foo.d = %d\n",fp->d);

}

void *thr_fn1(void *arg){
    struct foo foo={1,2,3,4};
    pr_foo("thread 1\n",&foo);
    pthread_exit((void*)&foo);
}

void *thr_fn2(void *arg){
    printf("thread 2: ID is %lu\n",(unsigned long)pthread_self());
    pthread_exit((void*)0);

}

int main(void){
    int err;
    pthread_t tid1,tid2;
    struct foo *fp; /*这个fp是共享的栈!*/

    err = pthread_create(&tid1,NULL,thr_fn1,NULL);
    if(err!=0)printf("cannot create thread 1 %d",err);
    err = pthread_join(tid1,(void*)&fp);
    if(err!=0)printf("cannot join thread 1 %d",err);
    sleep(1);

    printf("parent starting thread 2");
    err = pthread_create(&tid2,NULL,thr_fn2,NULL);
    if(err!=0)printf("cannot create thread 2 %d",err);
    
    sleep(1);
    pr_foo("parent:\n",fp); /*当主线程访问fp时,fp结构的内容(在tid1的栈上分配已经改变了)*/

    exit(0);

}


线程清理处理程序 thread cleanup handler code 11_5

#include "apue.h"
#include <pthread.h>


/*
线程可以安排它退出时需要调用的函数---》这样的函数称为线程清理处理程序(thread cleanup handler)
一个线程可以建立多个清理处理程序。
处理程序记录在栈中--》也就是,他们的执行顺序与他们注册时相反

    pthread_join()-->获取线程退出状态
*/

void cleanup(void *arg){
    printf("cleanup: %s\n",(char*)arg);
}

void* thr_fn1(void* arg){
    printf("thread 1 start\n");
    pthread_cleanup_push(cleanup,"thread 1 first handler");
    pthread_cleanup_push(cleanup,"thread 1 second handler");
    printf("thread 1 push complete\n");
    if(arg){
        return ((void*)1);
    }
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    
    return ((void*)1);

}

void* thr_fn2(void* arg){
    printf("thread 2 start\n");
    pthread_cleanup_push(cleanup,"thread 2 first handler");
    pthread_cleanup_push(cleanup,"thread 2 second handler");
    printf("thread 2 push complete\n");
    if(arg){
        return ((void*)2);
    }
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    
    return ((void*)2);

}

int main(void){
    int err;
    pthread_t tid1,tid2;
    void *tret;

    err = pthread_create(&tid1,NULL,thr_fn1,NULL);
    if(err!=0)printf("cannot create thread 1 %d",err);
    err = pthread_join(tid1,tret);
    if(err!=0)printf("cannot join thread 1 %d",err);

    printf("parent starting thread 2\n");
    err = pthread_create(&tid2,NULL,thr_fn2,NULL);
    if(err!=0)printf("cannot create thread 2 %d",err);
      err = pthread_join(tid2,tret);
    if(err!=0)printf("cannot join thread 2 %d",err);
   

    exit(0);
}

互斥锁 mutex code 11_10

#include<stdlib.h>
#include<pthread.h>

struct foo{
    int f_count;
    pthread_mutex_t f_lock;
    int f_id;

};
struct foo* foo_alloc(int id){

    struct foo *fp;
    if((fp = malloc(sizeof(struct foo))!=NULL))
        fp->f_count = 1;
        fp->f_id = id;
        if(pthread_mutex_init(&fp->f_lock,NULL)!=0){/* pthread_mutex_init()成功返回0 */
            free(fp);
            retrun NULL;
        }

}

void foo_hold(struct foo*fp){ /* add a reference to the object */
    pthread_mutex_lock(&fp->f_lock);
    fp->f_count++;
    pthread_mutex_unlock(&fp->f_lock);
}

void foo_rele(struct foo*fp) /* release a reference to the object */
{
    pthread_mutex_lock(&fp->f_lock);
    if(--fp->f_count ==0){ /* last reference */ 
        pthread_mutex_unlock(&fp->f_lock);
        pthread_mutex_destroy(&fp->f_lock);
        free(fp);
    }
    else{
        pthread_mutex_unlock(&fp->f_lock);
    }
};

合理安排锁粒度 code 11_11

/*
    防止死锁

*/
#include<stdlib.h>
#include<pthread.h>

#define NHASH 29
#define HASH(id) (((unsigned int)id)%NHASH)
struct foo{
    int f_count;
    pthread_mutex_t f_lock;
    int f_id;
    struct foo *f_next;/* protected by hashlock */

};

struct foo *fh[NHASH];

pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER;

struct foo* foo_alloc(int id){ /* allocate the object */

    struct foo *fp;
    int        idx;

    if((fp = malloc(sizeof(struct foo))!=NULL)){
         fp->f_count = 1;
        fp->f_id = id;
        if(pthread_mutex_init(&fp->f_lock,NULL)!=0){/* pthread_mutex_init()成功返回0 */
            free(fp);
            retrun NULL;
        }
    }
    idx = HASH(id);
    pthread_mutex_lock(&hashlock);
    fp->f_next = fh[idx];
    fh[idx] = fp;
    pthread_mutex_lock(&fp->f_lock);
    pthread_mutex_unlock(&hashlock);

    pthread_mutex_unlock(&fp->f_lock);
}

void foo_hold(struct foo*fp){ /* add a reference to the object */
    pthread_mutex_lock(&fp->f_lock);
    fp->f_count++;
    pthread_mutex_unlock(&fp->f_lock);
}

void foo_rele(struct foo*fp) /* release a reference to the object */
{
    struct foo *tfp;
    int         idx;

    pthread_mutex_lock(&fp->f_lock);
    if(fp->f_count ==1){ /* last reference */ 
        pthread_mutex_unlock(&fp->f_lock);
        pthread_mutex_lock(&hashlock);
        pthread_mutex_lock(&fp->f_lock);

        /* need to recheck the condition */
        if(fp->f_count!=1){
            fp->f_count--;
            pthread_mutex_unlock(&fp->f_lock);
            pthread_mutex_unlock(&hashlock);
            return ;
        }
        /* remove from list */
        idx = HASH(fp->f_id);
        tfp = fh[idx];
        if(tfp == fp){
            fh[idx] = fp->f_next;
        }
        else{
            while(tfp->f_next!=fp)
                tfp = tfp->f_next;
            tfp->f_next = fp->f_next;
        }
        pthread_mutex_unlock(&hashlock);
        pthread_mutex_unlock(&fp->f_lock);
        pthread_mutex_destroy(&fp->f_lock);
        free(fp);
    }
    else{
        fp->f_count--;
        pthread_mutex_unlock(&fp->f_lock);
    }
}

struct foo* foo_find(int id){/* find an existing object */

    struct foo *fp;

    pthread_mutex_lock(&hashlock);
    for(fp = fh[HASH(id)];fp!=NULL;fp=fp->f_next){
        if(fp->f_id == id){
            foo_hold(fp);
            break;
        }
    }
    pthread_mutex_unlock(&hashlock);
    return fp;

}


pthread_mutex_timelock()避免永久阻塞 code 11_13

/*

    使用函数 pthread_mutex_timedlock()避免永久阻塞
    
    当线程试图获取一个已加锁的互斥量时,pthread_mutex_timedlock互斥原语允许绑定线程阻塞时间
    当达到超时时间值时,pthread_mutex_timedlock不会对互斥量进行加锁,而是返回错误码 ETIMEOUT

output:

kali@kali:~/Desktop/Linux Study/Hellos/Chapter11$ ./TimeLock_11_13 
mutex is lock
current time is 05:36:40 AM
time is now 05:36:50 AM
cannot lock mutex again:Connection timed out
*/
#include "apue.h"

#include <pthread.h>
#include <time.h>

int main(void){
    int err;
    struct tm *tmp;
    struct timespec tout;

    char buf[64];
    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

    pthread_mutex_lock(&lock);
    printf("mutex is lock\n");

    clock_gettime(CLOCK_REALTIME,&tout);
    tmp = localtime(&tout.tv_sec);
    strftime(buf,sizeof(buf),"%r",tmp);
    printf("current time is %s\n",buf);

    tout.tv_sec+=10; /* 10 second from now */

    err = pthread_mutex_timedlock(&lock,&tout);
    clock_gettime(CLOCK_REALTIME,&tout);
    tmp = localtime(&tout.tv_sec);
    strftime(buf,sizeof(buf),"%r",tmp);
    printf("time is now %s\n",buf);

    if(err == 0){
        printf("mutex locked again!\n");
    }
    else{
        printf("cannot lock mutex again:%s\n",strerror(err));
    }
    exit(0);
}

使用屏障同步多个线程 code 11_16

/*
    屏障barria是用户协调多个线程并行工作的同步机制。
    屏障允许每个线程等待,直到所有的合作线程都达到某一点,然后从该点继续执行
    如:pthread_join()

    pthread_barrier_init()-->屏障初始化,为屏障分配资源
    pthread_barrier_destroy() --释放相应的资源
    pthread_barrier_wait() -->调用pthread_barrier_wait的线程在屏障计数,为满足条件时,
    会进入休眠状态。如果该线程是最后一个调用pthread_barrier_wait的线程,就满足了屏障技术,所有
    线程被唤醒。

output:

kali@kali:~/Desktop/Linux Study/Hellos/Chapter11$ ./Barrier_11_16 > sort.foo
kali@kali:~/Desktop/Linux Study/Hellos/Chapter11$ head -n 10 sort.foo 
sort took 0.0812 seconds
1210
3722
4686
5712
6700
8204
11425
18502
22619

*/

#include "apue.h"
#include <pthread.h>
#include <limits.h>
#include <sys/time.h>

#define NTHR 8
#define NUMNUM 800000L
#define TNUM (NUMNUM/NTHR)

long nums[NUMNUM];
long snums[NUMNUM];

pthread_barrier_t b;

//#ifdef SOLARIS
#define heapsort qsort
// #else
// extern int heapsort(void* ,size_t,size_t,int(*)(const void*,const void*));
// #endif

int comparelong(const void* arg1,const void*arg2){
    long l1 = *(long *)arg1;
    long l2 = *(long *)arg2;

    if(l1==l2)return 0;
    else if(l1<l2) return -1;
    else return 1;
}

/*
    Worker thread to sort a portion of the set of numbers
*/
void* thr_fn(void *arg){
    long idx = (long)arg;
    heapsort(&nums[idx],TNUM,sizeof(long),comparelong);
    pthread_barrier_wait(&b);

    return ((void*)0);
}

void merge(){
    long idx[NTHR];
    long i,minidx,sidx,num;
    for (int i = 0; i < NTHR; i++)
    {
        idx[i]= i*TNUM;
    }
    for(sidx = 0;sidx <NUMNUM;sidx++){
        num = LONG_MAX;
        for (int i = 0; i < NTHR; i++)
        {
            if((idx[i]<(i+1)*TNUM)&&(nums[idx[i]]<num)){
                num = nums[idx[i]];
                minidx = i;
            }
        }
        snums[sidx] =nums[idx[minidx]];
        idx[minidx]++;
        
    }


}

int main(){

    unsigned long i;
    struct timeval start,end;
    long long startusec,endusec;
    double elapsed;
    int err;
    pthread_t tid;

    /* 
        Create the initial set of numbers to sort
    */
    srandom(1);
    for (int i = 0; i < NUMNUM; i++)
    {
        nums[i] = random();
    }
    
    /*
        Create 8 threads to sort the numbers
    */
   gettimeofday(&start,NULL);
   pthread_barrier_init(&b,NULL,NTHR+1);

   for (int i = 0; i < NTHR; i++)
   {
       err = pthread_create(&tid,NULL,thr_fn,(void*)(i*TNUM));
       if(err!=0)
            printf("cannot creat thread\n");
   }
    pthread_barrier_wait(&b);
    merge();
    gettimeofday(&end,NULL);

    /*
        print the sorted list
    */
   startusec = start.tv_sec*1000000+start.tv_usec;
   endusec = end.tv_sec*1000000+end.tv_usec;
   elapsed = (double)(endusec-startusec)/1000000.0;
   printf("sort took %.4f seconds\n",elapsed);

   for (int i = 0; i < NUMNUM; i++)
   {
       printf("%ld\n",snums[i]);
   }
   exit(0);
   



}




猜你喜欢

转载自blog.csdn.net/qq_32095699/article/details/106771635