linux多线程-懒人笔记(一)

本文是关于Linux多线程编程的个人笔记,重点介绍了线程特点、进程空间、线程退出方式、pthread函数、线程同步与互斥量、条件变量等内容。通过示例代码探讨了线程同步问题,尤其是pthread_cond_wait和pthread_cond_signal的使用,以及避免竞争条件的方法。
摘要由CSDN通过智能技术生成

本文为自己的懒人笔记,没怎么梳理。看到什么小点,就写了什么小点。

懒人笔记

1.进程空间:
text:只读,包括常量
data: stack heap static
bss:未初始化的全部变量,静态变量

2.线程的特点是只具有自己的堆栈区
其他空间全部共享,所以,线程并不是没有自己空间的,如果堆栈的变量想要传递就没法直接共享。

3.主线程一旦退出,进程结束。
所以,多线程的时候,如果主线程退出,那么进程空间回收。其他线程歇菜。
线程的特点还是开销比较小。

4.线程有三种退出方式:
线程可以简单的从启动例程中返回,返回值是线程的退出码。
线程可以被同一进程中的其他线程取消。
线程调用pthread_exit();

5.pthread_self()获取线程id.
注意返回值是 unsigned long int,所以打印的时候要使用%lu方式。
为什么线程退出:一定是pthread_exit或者是简单退出,不能是exit
因为后者是进程退出,只要线程调用该函数,进程空间回收,所有资源都没有了。

6.进程退出注意两个点:
1.不能用exit退出,这是退出进程。整个线程都将被销毁
2.资源要回收。

7.说起资源回收,也是和进程的不同。
进程的资源回收必须是父进程,但是线程可以主线程回收,也可以系统去回收。
线程有两种状态,joinable and detatch

8.这一对好朋友需要说一下:
void pthread_exit(void* retval);
void pthread_join( pthread_t thread, void** retval );
一个返回,一个接受。到底什么关系。
先说pthread_exit, 粘一段手册的内容:
The value pointed to by retval should not be located on the calling thread’s stack, since the contents of that stack are undefined after the thread terminates.
也就是说,retval其实是返回值的地址,是一个传出参数。
再说pthread_join,主要是弄清楚,为什么是void**类型。因为对于pthread_exit的传出参数retval来说,pthread_join其实获取的是这个值,但是如果在主线程当中想要获取这个值,那只能把这个值传出去。因此,需要一个传出参数。那就只能是retval这个变量的地址,因此是type(&retval)类型,即void* 类型.

9.calloc需要初始化,malloc则不需要初始化。

10.int pthread_cancle( pthread_t thread );对于这个函数而言,也是线程退出的一种方式。先初步了解,手册是这么说的:send a cancellation request to a thread.注意,只是send a caccellation request,thread不是立即退出。它必须得到cancellation point才可以退出终止。
一般而言根据POSIX标准,pthread_join()、pthread_testcancel()、pthread_cond_wait()、pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及read()、write()等会引起阻塞的系统调用都是Cancelation-point,而其他pthread函数都不会引起Cancelation动作。

11.说一个用它的场景:
考虑这样一个问题。
现在有10000个人,每个人的名字都不一样。
我现在需要找到 kang这个人,假设这个人一定存在的。
那么怎么找?
第一种办法:枚举,当然不好。因为量很大。
其次,多线程。
thd1: 1-1000
thd2; 1001 - 2000
….

thd10 - 9000-10000
假设现在这个人的编号是1234,那么第二个想成找到之后返回,其他线程没有必要找了。
主线程可以把其他线程杀死。

12.线程终止清理函数,主要是在线程异常终止,还没回收资源,就被释放了。
所以,资源没有回收,利用清理函数。

13.线程最麻烦的是,如果有一个线程异常退出了,那么整个进程都会退出。这会导致其他线程也异常退出,整个系统挂掉。
但是,多进程就不会出现这个问题。

14.注意一点,pthread_create失败返回非0,不是-1.小心

15.对共享变量的访问,没有办法是原子操作,导致操作异常。
try_lock()加锁不成功时,不会阻塞。通过返回值判断一下。
锁的初始化有静态和动态两种形式。
一般使用动态。

16.
void* thread_handle( void* arg ){
printf( “thread: %lu\n”, pthread_self() );
int* pcnt = (int*)arg;
int cnt = *pcnt;
while(cnt–){
++g_val;
}
printf( “hello,world” ); // 这里这么写也是 不行的!!!
pthread_exit(NULL);
}
因为本质上他们都访问了stdout这个文件,相当于读者-写者问题。不行。

代码


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void err_handle(const char* msg){
    perror(msg);
    exit(1);
}

void* thread_handle( void* arg ){
    char* msg = (char*)arg;

    printf( "thread: %s\n", msg );
    printf( "thread id: %lu\n", pthread_self() );

    int fds[2];
    pipe(fds);
    char buf[1024];
    read( fds[0], buf, 1023 );
    /*
    char* ret_msg = "how are you!\n";

    pthread_exit((void*)ret_msg); // return
    */

    /*
    int* ret_val = (int*)malloc( sizeof(int) * 1 );
    *ret_val = 1024;
    if(!ret_val){
        err_handle("malloc");
    }

    pthread_exit( (int*)ret_val );
    */
    pthread_exit(NULL);
}

int main( int argc, char* argv[] ){
    pthread_t tid;
    int ret = 0;
    char* s = "hello,world!";

    printf( "main id: %lu\n", pthread_self() );
    ret = pthread_create( &tid, NULL, thread_handle, (void*)s  );
    if(-1 == ret){
        err_handle("pthread_create");
    }
    /*这个是通常情况下退出,不需要线程的返回参数。
    ret = pthread_join(tid, NULL);
    if(-1 == ret){
        err_handle("pthread_join");
    }
    printf( "Thread join!\n" );
    */

    /*
    char* ret_msg = NULL;
    ret = pthread_join(tid, (void**)&ret_msg);
    if(-1 == ret){
        err_handle("pthread_join");
    }
    printf("thread has finished, retval is %s\n", ret_msg);
    exit(EXIT_SUCCESS);
    */

    /*
    int* ret_val = NULL;
    ret = pthread_join( tid, (void**)&ret_val );
    if(-1==ret){
        err_handle("pthread_join");
    }
    printf( "thread join: ret_val is %d\n", *ret_val );
    */
    pthread_cancel(tid);

    exit(EXIT_SUCCESS);
}

代码

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define N 2 // thread num

void err_handle(const char* msg){
    perror(msg);
    exit(EXIT_FAILURE);
}

void* thread_handle(void* arg);


int g_val = 0; // global variable

typedef struct task{
    int cnt;
    pthread_mutex_t* pmylock;
}task_t,*ptask;


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

    pthread_t tid_arr[N];
    int i = 0;
    int ret = 0;

    int cnt = 100000000;
    pthread_mutex_t mylock;
    ret = pthread_mutex_init(&mylock, NULL);
    if(ret){
        err_handle("pthread_mutex_init");
        exit(EXIT_FAILURE);
    }

    task_t a_task;
    a_task.cnt = cnt;
    a_task.pmylock = &mylock;

    for(i = 0; i < N; ++i){
        ret = pthread_create( tid_arr + i, NULL, thread_handle, (void*)&a_task  );
        if(0 != ret) err_handle("pthread_create");
    }

    for(i = 0; i < N; ++i){
        ret = pthread_join(tid_arr[i], NULL);
        if(-1 == ret) err_handle("pthread_join");
    }

    ret = pthread_mutex_destroy(&mylock);
    if(ret){
        err_handle("pthread_mutex_destroy");
        exit(EXIT_FAILURE);
    }
    printf( "main: %lu\n", pthread_self() );
    printf("g_val = %d\n", g_val);
    exit(EXIT_SUCCESS);
}

void* thread_handle(void* arg){

    ptask p_a_task = (ptask)arg;
    int cnt = p_a_task->cnt;

    int i;
    pthread_mutex_lock(p_a_task->pmylock);
    for(i = 0; i < cnt; ++i){
        ++g_val;
    }
    pthread_mutex_unlock(p_a_task->pmylock);
    printf("thread: %lu\n", pthread_self());
    pthread_exit(NULL);
}

代码

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

void err_msg( int en , const char* msg );
void err_msg1( const char* msg );
void err_msg2( const char* msg );

void* thread_handle( void* );

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

    pthread_t tid = 0;
    int ret = 0;
    int i = 0;
    int ret_val = 0; // 返回值这里,线程返回什么类型,这里写什么类型即可。其实应该写int* ret_val;但是线程返回值不是指针类型,它是直接把值类型,强转。因为,指针变量和整型变量都是占4个字节,所以虽然这么转不是非常纯正,但是并不会出错。语义不好,但是可以实现。


    ret = pthread_create(&tid, NULL, thread_handle, NULL );
    if( 0 != ret ){
        err_msg(ret, "pthread_create");
    }


    for( i = 0; i < 10; ++i ){
        printf( "%lu : hello my child!\n", pthread_self() );
        if(5==i)
            pthread_cancle(tid);
        sleep(1);
    }



    ret = pthread_join(tid, (void**)&ret_val);
    if( 0 != ret ){
        err_msg(ret, "pthread_join");
    }
    printf( "%lu: Thread is joined, retval is %d\n", pthread_self(), ret_val );
    exit(EXIT_SUCCESS);
}

void err_msg( int en, const char* msg ){
    errno = en;
    perror(msg);
    exit(EXIT_FAILURE);
}
void err_msg1( const char* msg ){
    perror(msg);
    exit(EXIT_FAILURE);
}
void err_msg2( const char* msg ){
    fprintf(stderr, "%s\n", msg );
    exit(EXIT_FAILURE);
}
void* thread_handle( void* arg){

    int i = 0;
    char* msg = (char*)malloc( sizeof(char) * 32 );
    if(!msg)
        err_msg2("Not enough space!");


    for( i = 0; i < 10; ++i ){
        printf( "%lu: Hello, my father!\n", pthread_self() );
        sleep(1);
    }

    free(msg);
    printf("Dynamic space is freed!\n");
    pthread_exit((void*)10);
}

代码

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

void err_msg( int en , const char* msg );
void err_msg1( const char* msg );
void err_msg2( const char* msg );

void* thread_handle( void* );

int main( int argc, char* arg
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值