UNIX环境高级编程-线程

目录

相关函数列表

注意事项

一个创建线程的例子

用clone函数实现线程 

线程互斥的例子

带超时的互斥程序

读写锁的例子

一个条件变量的例子(可用于生产者-消费者模式)

自旋锁

barrier模式

进程和线程原语的比较

参考


 

 

相关函数列表

//对两个线程ID进行比较  
//若相等返回非0数值,否则返回0  
#include <pthread.h>  
int pthread_equal(pthread_t tid1, pthread_t tid2);  
  
//获得线程自身的ID  
#include <pthread.h>  
pthread_t pthread_self(void);  
  
//创建新线程  
//pthread_attr_t用来定制各种不同的线程属性,新线程函数从start_rtn函数的地址开始运行,如果  
//要向start_rtn传递参数,需要将这些参数放入结构体中,然后将此将结构体地址作为arg参数传入  
#include <pthread.h>  
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr,  
                   void *(*strt_rtn)(void *), void *restrict arg);  
  
//单个线程可以通过3种方式退出  
//1.线程可以简单地从启动例程种返回,返回值是线程的退出码  
//2.线程可以被同一进程中的其他线程取消  
//3.线程调用pthread_exit  
#include <pthread.h>  
void pthread_exit(void *rval_ptr);  
  
//进程中的其他线程可以通过调用下列函数来访问这个 rval_ptr指针  
//如果对线程的返回值不感兴趣,可以把rval_ptr设置为NULL,这样等于等待线程终止,但是不获取  
//线程终止状态  
#include <pthread.h>  
int pthread_join(pthread_t thread, void **rval_ptr);  
  
  
//线程取消  
#include <pthread.h>  
int pthread_cancel(pthread_t tid);  
  
//可以安排一些清理函数,类似进程的atexit函数,这样的函数被称为线程清理处理程序(thread   
//cleanup handler),一个线程可以建立多个清理处理程序,其执行顺序和注册顺序相反  
#include <pthread.h>  
void pthread_cleanup_push(void (*rtn)(void *), void *arg);  
void pthread_cleanup_pop(int execute);  
  
//分离线程  
#include <pthread.h>  
int pthread_detach(pthread_t tid);  
  
  
//互斥量  
//如果不希望被阻塞使用trylock函数,不出现阻塞直接返回0,否则就会失败不能锁住返回EBUSY  
//timelock函数指定一个绝对时间(在X到达之前可以阻塞,而不是等待Y秒)  
#include <pthread.h>  
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);  
int pthread_mutex_destroy(pthread_mutex_t *mutex);  
int pthread_mutex_lock(pthread_mutex_t *mutex);  
int pthread_mutex_trylock(pthread_mutex_t *mutex);  
int pthread_mutex_unlock(pthread_mutex_t *mutex);  
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict tsptr);  
  
  
//读写锁  
#include <pthread.h>  
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock);  
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);  
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);  
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);  
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);  
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);  
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);  
int pthread_rwlock_timerdlock(pthread_rwlock_t *restrict rwlock, const struct   
                              timespec *restrict tsptr);  
int pthread_rwlock_timewrlock(pthread_rwlock_t *restrict rwlock, const struct  
                              timespec *restrict tsptr);  
  
  
//条件变量  
#include <pthread.h>  
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread-condattr_t *restrict attr);  
int pthread_cond_destroy(pthread_cond_t *cond);  
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex *restrict mutex);  
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex,  
                           const struct timespec *restrict tsptr);  
int pthread_cond_signal(pthread_cond_t *cond);  
int pthread_cond_broadcast(pthread_cond_t *cond);  
  
  
//自旋锁  
#include <pthread.h>  
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);  
int pthread_spin_destroy(pthread_spinlock_t *lock);  
int pthread_spin_lock(pthread_spinlock_t *lock);  
int pthread_spin_trylock(pthread_spinlock_t *lock);  
int pthread_spin_unlock(pthread_spinlock_t *lock);  
  
  
//屏障  
#include <pthread.h>  
int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthread_barrierattr_t   
                         *restrict attr, unsigned int count);  
int pthread_barrier_destroy(pthred_barrier_t *barrier);  
int pthread_barrier_wait(pthread_barrier_t *barrier);  

 

注意事项

不要用直接操作pthread_t结构体

这样会导致代码不可移植,初始化结构体后,用相关函数操作

同样,pthread.h中的其他结构体也不要直接操作,初始化好之后用相关函数操作

因为pthread不是linux的标准库,所以GCC编译时,需要加上 -lpthread参数

 

一个创建线程的例子

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

void clearn(void *msg) {
    printf("clean %s\n",(char*)msg);
}

//线程回调函数f1
void *f1(void *arg) {
    printf("thread f1 startup...\n");
    //注册一个清理函数
    pthread_cleanup_push(clearn,"f1-> 11111");
    pthread_cleanup_push(clearn,"f1-> 22222");
    if(arg) {
        return ((void *)1);
    }
    //删除清理hook
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    return ((void *)1);
    
}

//线程回调函数f1
void *f2(void *arg) {
    printf("thread f2 startup...\n");
    pthread_cleanup_push(clearn,"f2-> 11111");
    pthread_cleanup_push(clearn,"f2-> 22222");
    if(arg) {
        pthread_exit((void *)2);
    }
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    pthread_exit((void*)2);
    return ((void *)2);
}


int main(int argc, char *argv[]) {
    pthread_t p1,p2;
    void* ret; 
    //在main中创建两个线程
    pthread_create(&p1,NULL,f1,(void*)1);
    pthread_create(&p2,NULL,f2,(void*)2);

    //main线程join,等待线程f1的结束
    pthread_join(p1,&ret);
    printf("thread 1 exit code %d\n",ret);

    pthread_join(p2,&ret);
    printf("thread 2 exit code %d\n",ret);
}

//编译
gcc -lpthread -o p2 p2.c 

//执行结果
thread f1 startup...
thread 1 exit code 1
thread f2 startup...
clean f2-> 22222
clean f2-> 11111
thread 2 exit code 2

//用strace分析程序
//pthread_create是用clone实现的,pthread_join是用futex实现的
...
clone(child_stack=0x7f852e106fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f852e1079d0, tls=0x7f852e107700, child_tidptr=0x7f852e1079d0) = 13937
futex(0x7f852e9089d0, FUTEX_WAIT, 13936, NULLstrace: Process 13936 attached
...

 

用clone函数实现线程 

java中创建线程也是用clone实现的,线程之间的同步也是用futex实现的,因为最终调用的c的函数

#include <unistd.h>
#include <sys/syscall.h> /* For SYS_xxx definitions */
#include <sys/types.h>
#include <sched.h>
#include <sys/mman.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
 
#define STACK_SIZE 1024*1024*8 
 
int thread_func(void *lparam) {
    printf("thread id %d \n", (int)syscall(SYS_gettid));
    printf("thread get param : %d \n", (int*)lparam);
    sleep(1);
    return 0;
}
 
 
void child_handler(int sig) {
    printf("I got a SIGCHLD\n");
}
 
int main(int argc, char **argv) {
    setvbuf(stdout, NULL, _IONBF, 0); 
    signal(SIGCHLD, child_handler);
    
 
    void *pstack = (void *)mmap(NULL,
                                STACK_SIZE,PROT_READ | PROT_WRITE ,
                              MAP_PRIVATE | MAP_ANONYMOUS | MAP_ANON ,//| MAP_GROWSDOWN ,
                                -1,
                                0);
    if (MAP_FAILED != pstack) {
        int ret;
        printf("strace addr : 0x%X\n", (int*)pstack);

        ret = clone(thread_func,
                    (void *)((unsigned char *)pstack + STACK_SIZE),
                    CLONE_VM | CLONE_FS | CLONE_THREAD | CLONE_FILES | CLONE_SIGHAND | SIGCHLD,
                    (void *)NULL);
        if (-1 != ret) {
            pid_t pid = 0;
            printf("start thread %d \n", ret);
            sleep(5);
            pid = waitpid(-1, NULL, __WCLONE | __WALL);
            printf("child : %d exit %s\n", pid,strerror(errno));
        }
        else {
            printf("clone failed %s\n", strerror(errno) );
        }
    }
    else {
        printf("mmap() failed %s\n", strerror(errno));
    }
    return 0;
}

 

线程互斥的例子

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

pthread_mutex_t mutex;
int num = 100;
void lock() {
    pthread_mutex_lock(&mutex);
}

void unlock() {
    pthread_mutex_unlock(&mutex);
}


void *f1(void *msg) {
    lock();
    sleep(3);
    num++;
    unlock();
    printf("11111111111111 ok\n");
    pthread_exit(NULL);
}


void *f2(void *msg) {
    lock();
    sleep(2);
    num++;
    unlock();
    printf("222222222222222 ok\n");
    pthread_exit(NULL);
}


int main(int argc, char *argv[]) {

    pthread_t p1,p2;
    void *ret1,*ret2;
 
    pthread_mutex_init(&mutex,NULL);
    pthread_create(&p1,NULL,f1,(void*)1);
    pthread_create(&p2,NULL,f2,(void*)2);
      
    pthread_join(p1,&ret1);
    pthread_join(p2,&ret2);

    pthread_mutex_destroy(&mutex);

    printf("num=%d\n",num);
}

//执行结果
11111111111111 ok
222222222222222 ok
num=102

//strace分析程序
clone(child_stack=0x7fa128e6efb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fa128e6f9d0, tls=0x7fa128e6f700, child_tidptr=0x7fa128e6f9d0) = 14611
...
clone(child_stack=0x7fa12866dfb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fa12866e9d0, tls=0x7fa12866e700, child_tidptr=0x7fa12866e9d0) = 14612
...
futex(0x7fa128e6f9d0, FUTEX_WAIT, 14611, NULLstrace: Process 14611 attached
...
[pid 14611] futex(0x6010a0, FUTEX_WAKE_PRIVATE, 1) = 1
[pid 14612] futex(0x6010a0, FUTEX_WAKE_PRIVATE, 1) = 0
[pid 14612] write(1, "222222222222222 ok\n", 19222222222222222 ok
) = 19

//madvise()这个函数可以对映射的内存提出使用建议,从而提高内存。
[pid 14612] madvise(0x7fa127e6e000, 8368128, MADV_DONTNEED) = 0
...

 

 

带超时的互斥程序

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#define false 0
#define true 1
#define bool int

pthread_mutex_t mutex;

void lock() {
    pthread_mutex_lock(&mutex);
}

void unlock() {
    pthread_mutex_unlock(&mutex);
}

bool lock_timeout(int second) {
    struct timespec tout;
    clock_gettime(CLOCK_REALTIME,&tout);
    tout.tv_sec += second;
    int err;
    err = pthread_mutex_timedlock(&mutex,&tout);
    if(err == 0) {
        printf("mutex lock ok!\n");
        return true;
    } else {
        printf("mutex lock failure!\n");
        return false;
    }
}

void *f1(void *arg) {
    lock();
    sleep(10);
    printf("f1...\n");
    unlock();
    pthread_exit(NULL);
}

void *f2(void *arg) {
    sleep(2);
    if(lock_timeout(3)) {
        printf("f2 ok...\n");
    } else {
        printf("f2 failure\n");
    }
    unlock();
    pthread_exit(NULL);
}


int main(int argc, char *argv[]) {
    pthread_t p1,p2;
    void *ret1,*ret2;
    pthread_mutex_init(&mutex,NULL);
    pthread_create(&p1,NULL,f1,(void*)1);
    pthread_create(&p2,NULL,f2,(void*)2);
    pthread_join(p1,&ret1);
    pthread_join(p2,&ret2);
    pthread_mutex_destroy(&mutex);
    printf("main ok...\n");
}

//运行结果
mutex lock failure!
f2 failure
f1...
main ok...

//用strace分析程序
//超时也是用futex实现的
。。。
futex(0x6010c0, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 2, {1541943304, 588528513}, ffffffff) = -1 ETIMEDOUT (Connection timed out)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0257e05000
write(1, "mutex lock failure!\n", 20mutex lock failure!) = 20
write(1, "f2 failure\n", 11f2 failure) = 11
。。。

 

 

读写锁的例子

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#define false 0
#define true 1
#define bool int

pthread_rwlock_t  rw_lock;

void read_lock() {
    pthread_rwlock_rdlock(&rw_lock);
}

void write_lock() {
    pthread_rwlock_wrlock(&rw_lock);
}

void unlock() {
    pthread_rwlock_unlock(&rw_lock);
}


void *f1_r(void *arg) {
    read_lock();
    sleep(5);
    printf("f1_r ok\n");
    unlock();
    pthread_exit(NULL);
}

void *f2_r(void *arg) {
    read_lock();
    sleep(3);
    printf("f2_r ok\n");
    unlock();
    pthread_exit(NULL);
}

void *f3_w(void *arg) {
    sleep(1);
    write_lock();
    sleep(2);
    printf("f3_w ok\n");
    unlock();
    pthread_exit(NULL);
}


int main(int argc, char *argv[]) {
    pthread_t p1,p2,p3;
    void *ret1, *ret2, *ret3;
    pthread_rwlock_init(&rw_lock,NULL);
    pthread_create(&p1,NULL,f1_r,(void*)1);
    pthread_create(&p2,NULL,f2_r,(void*)2);
    pthread_create(&p3,NULL,f3_w,(void*)3);


    pthread_join(p1,&ret1);
    pthread_join(p2,&ret2);
    pthread_join(p3,&ret3);
    pthread_rwlock_destroy(&rw_lock);
    return 0;
}

//执行结果
f2_r ok
f1_r ok
f3_w ok

//用strace分析
...
会出现三次clone函数调用
...
futex(0x7f4797f54190, FUTEX_WAKE_PRIVATE, 2147483647) = 0
write(1, "f1_r ok\n", 8f1_r ok)    = 8
futex(0x6010ac, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
...

 

 

一个条件变量的例子(可用于生产者-消费者模式)

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <string.h>
#define false 0
#define true 1
#define bool int


pthread_mutex_t mutex;
pthread_cond_t cond;
char *msg;

void lock() {
    pthread_mutex_lock(&mutex);
}

void unlock() {
    pthread_mutex_unlock(&mutex);
}

void wait() {
    pthread_cond_wait(&cond,&mutex);
}

void signal() {
    pthread_cond_signal(&cond);
}

void signal_all() {
    pthread_cond_broadcast(&cond);
}


void *f1() {
    lock();
    sleep(5);
    if( strcmp(msg,"ok") ==0 ) {
        printf("f1... strcmp ok\n");
        signal();
    }
    else {
        printf("f1... not equals set -> ok\n");
        memcpy(msg,"ok",2);
    }
    unlock();
    pthread_exit(NULL);
}

void *f2() {
    lock();
    sleep(3);
    if( strcmp(msg,"ok") != 0 ) {
        printf("f2... strcmp not equals\n");
        wait();
    } 
    else {
        printf("f2... equals\n");
        signal();
    }
    unlock();
    pthread_exit(NULL);
}


int main(int argc, char *argv[]) {

    pthread_t p1,p2;
    void *ret1, *ret2;
    msg = (char*)malloc(sizeof(char)*10);   

    pthread_create(&p1,NULL,f1,(void*)1);
    pthread_create(&p2,NULL,f2,(void*)2);

    pthread_join(p1,&ret1);
    pthread_join(p2,&ret2);
    pthread_cond_destroy(&cond);
    pthread_rwlock_destroy(&mutex);
    printf("end main...\n");
    return 0;
}


//执行结果
f1... not equals set -> ok
f2... equals
end main...

//用strace分析程序,也是用futex实现的
...
futex(0x6020c0, FUTEX_WAKE_PRIVATE, 1) = 1
...
futex(0x7f443a27a9d0, FUTEX_WAIT, 19266, NULL
...

 

自旋锁

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <string.h>
#define false 0
#define true 1
#define bool int

pthread_spinlock_t  mutex;
int num =0;

void lock() {
    pthread_spin_lock(&mutex);
}

void try_lock() {
    pthread_spin_trylock(&mutex);
}

void unlock() {
    pthread_spin_unlock(&mutex);
}


void *f1(void *msg) {
    int i=0;
    for(;i<10;i++) {
        lock();
        num++;
        unlock();
    }
    printf("f1 ok\n");
    pthread_exit(NULL);
}


void *f2(void *msg) {
    int i=0;
    for(;i<100;i++) {
        lock();
        num++;
        unlock();
    }
    printf("f2 ok\n");
    pthread_exit(NULL);
}


int main(int argc, char *argv[]) {

    pthread_t p1,p2;
    void *ret1, *ret2;
    pthread_spin_init(&mutex,PTHREAD_PROCESS_PRIVATE);
    pthread_create(&p1,NULL,f1,(void*)1);
    pthread_create(&p2,NULL,f2,(void*)2);
    
    printf("##################################################");
    pthread_join(p1,&ret1);
    pthread_join(p2,&ret2);
    pthread_spin_destroy(&mutex);
    printf("num -> %d\n",num);
    return 0;

}

 

barrier模式

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <string.h>
#define false 0
#define true 1
#define bool int

pthread_barrier_t barrier;
pthread_mutex_t mutex;
pthread_cond_t cond;
int barrier_num = 3;
int num;


void lock() {
    pthread_mutex_lock(&mutex);
}

void unlock() {
    pthread_mutex_unlock(&mutex);
}


void *f1() {
    lock();
    num++;
    barrier_num--;
    unlock();
    printf("f1 ok %x\n",pthread_self());
    pthread_barrier_wait(&barrier);
    if(barrier_num==0) {
        printf("f1 notify\n");
        pthread_cond_signal(&cond);
    }
    pthread_exit(NULL);
}


void *f2() {
    lock();
    num++;
    barrier_num--;
    unlock();
    printf("f2 ok %x\n",pthread_self());
    pthread_barrier_wait(&barrier);
    if(barrier_num==0) {
        printf("f2 notify\n");
        pthread_cond_signal(&cond);
    }
    pthread_exit(NULL);
}


void *f3() {
    lock();
    num++;
    barrier_num--;
    unlock();
    printf("f3 ok %x\n",pthread_self());
    pthread_barrier_wait(&barrier);
    if(barrier_num==0) {
        printf("f3 notify\n");
        pthread_cond_signal(&cond);
    }
    pthread_exit(NULL);
}


void *reduce() {
    printf("pre reduce\n");
    lock();
    printf("reduce wait\n");
    pthread_cond_wait(&cond,&mutex);
    unlock();
    printf("reduce sum -> %d\n",num);
}


int main(int argc, char *argv[]) {

    pthread_t p1,p2,p3,p4;
    void *ret1, *ret2, *ret3, *ret4;
 
    pthread_mutex_init(&mutex,NULL);
    pthread_barrier_init(&barrier,NULL,barrier_num);

    pthread_create(&p1,NULL,f1,(void*)1);
    pthread_create(&p2,NULL,f2,(void*)2);
    pthread_create(&p3,NULL,f3,(void*)3);
    pthread_create(&p4,NULL,reduce,(void*)4);


    pthread_join(p1,&ret1);
    pthread_join(p2,&ret2);
    pthread_join(p3,&ret3);
    pthread_join(p4,&ret4);
    pthread_mutex_destroy(&mutex);
    pthread_barrier_destroy(&barrier);

    printf("main end... %x\n",pthread_self());
    return 0;
}

//运行结果
f1 ok 86c7f700
f2 ok 8647e700
f3 ok 85c7d700
f3 notify
pre reduce
reduce wait
f2 notify
reduce sum -> 3
f1 notify
main end... 87474740

 

进程和线程原语的比较

进程原语线程原语描述
forkpthread_create创建新的控制流
exitpthread_exit从现有的控制流中退出
waitpidpthread_join从控制流中得到退出状态
atexitpthread_cancel_push注册在退出控制流时调用的函数
getpidpthread_self获取控制流的ID
abortpthread_cancel请求控制流的非正常退出

 

 

 

 

参考

undefined reference to 'pthread_create'问题解决

Linux 中使用 clone 函数来创建线程

Linux 中使用 clone 函数

futex 手册摘要

threadpool —— 基于 pthread 实现的简单线程池

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值