Linux多线程笔记一

Linux多线程笔记一

基础知识

  1. 进程是资源管理的最小单位,线程是程序执行的最小单位。
  2. 每个进程有自己的数据段、代码段和堆栈段。
    线程它包含独立的栈和CPU寄存器状态,线程是进程的一条执行路径。
    每个线程共享其所附属进程的所有资源,包括打开的文件、内存页面信号标识及动态分配的内存等。
  3. 线程是属于进程的,线程运行在进程空闻内,同一进程所产生的线程共享同一用户内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。一个进程至少需要一个线程作为它的指令执行体,进程管理着资源(比如cpu、内存、文件等等)。而将线程分配到某个cpu上执行。

线程基本方法

  1. pthread_create 新建线程;
  2. pthread_self 获取线程id;
  3. pthread_exit 退出一个线程;
  4. pthread_join 等待线程结束

新建一个线程,打印hello world:

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

void* myfunc(void* args) {
        printf("Hello world!\n");
        return NULL;
}

int main() {
        pthread_t th;
        pthread_create(&th, NULL, myfunc, NULL);
        // wait thread finish
        pthread_join(th, NULL); 
        return 0;
}

获取线程id:

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

int main() {
    printf("main thread id is: %lu\n", pthread_self());
    return 0;
}

thread_t 定义在 /usr/include/bits/pthreadtypes.h

/* Thread identifiers.  The structure of the attribute type is not
   exposed on purpose.  */
typedef unsigned long int pthread_t;

子线程获取自身id和主线程不同:

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

void* myfunc(void* args) {
        printf("child thread id is: %lu\n", pthread_self());
        printf("Hello world!\n");
        return NULL;
}

int main() {
        pthread_t th;
        pthread_create(&th, NULL, myfunc, NULL);
        printf("main thread id is: %lu\n", pthread_self());
        // wait thread finish
        pthread_join(th, NULL); 
        return 0;
}

比较线程id不同:

使用 pthread_equal函数

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

void* cmp_thread_id(void* args) {
    pthread_t th = pthread_self();
    pthread_t main_th = *(pthread_t*)args;
    printf("ptread_equal return : %d whit args %lu and %lu\n", pthread_equal(th, main_th), th, main_th);
    return NULL;
}

int main() {
    pthread_t th;
    pthread_t main_id = pthread_self();
    pthread_create(&th, NULL, cmp_thread_id, (void*)&main_id);
    // wait thread finish
    pthread_join(th, NULL);
    return 0;
}

新建两个线程,分别打印1-100:

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


void* myfunc(void* args) {
    int i;
    for (i = 0; i < 100; i++) {
        printf("Hello world %d from %s!\n", i, (char*)args);
        // sleep 0.1s
        sleep(0.1);
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    pthread_create(&thread1, NULL, myfunc, "thread1");
    pthread_create(&thread2, NULL, myfunc, "thread2");

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    return 0;
}

线程终止:

#include <stdio.h>

#include <stdlib.h>

void* sum_func(void* args) {
    int stop_num = *(int*)args;
    for (int i = 0; i < 100; i++) {
        if (i == stop_num) {
            pthread_exit(args);
        }
    }
    printf("never run here\n");
    return NULL;
}

int main() { 
    pthread_t th1;
    int stop_num = 9 * 9;
    pthread_create(&th1, NULL, sum_func, (void*)&stop_num);
    int ret_stop_num = 0;
    int* p_t = &ret_stop_num;
    pthread_join(th1, (void*)&p_t);
    printf("thread ret val is %d\n", *p_t);
    return 0;
}

注意:

void pthread_exit(void *retval);

参数retval不能是在线程调用的栈上的指针,因为线程结束后就不存在了。

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.

所以以下代码有问题:

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

#include <stdlib.h>

void* sum_func(void* args) {
    int stop_num = *(int*)args;
    int ret_val = 0;
    for (int i = 0; i < 100; i++) {
        if (i == stop_num) {
                ret_val = i;
                pthread_exit((void*)&ret_val);
        }
    }
    printf("never run here\n");
    return NULL;
}

int main() {
    pthread_t th1;
    int stop_num = 9 * 9;
    pthread_create(&th1, NULL, sum_func, (void*)&stop_num);
    int ret_stop_num = 0;
    int* p_t = &ret_stop_num;
    pthread_join(th1, (void*)&p_t);
    printf("thread ret val is %d\n", *p_t);
    return 0;
}

会返回一个32764附近的值,具体原因未知。

使用chatgpt给的实例,看起来也有问题:

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

void *thread_func(void *arg)
{
    int num = *(int *)arg;
    printf("Thread %d started. will return num: %d\n", num, num);
    pthread_exit((void *)&num);
}

int main()
{
    pthread_t thread1, thread2;
    int arg1 = 1, arg2 = 2;

    pthread_create(&thread1, NULL, &thread_func, (void *)&arg1);
    pthread_create(&thread2, NULL, &thread_func, (void *)&arg2);

    void *res1, *res2;
    pthread_join(thread1, &res1);
    pthread_join(thread2, &res2);

    printf("Thread 1 returned %d.\n", *(int *)res1);
    printf("Thread 2 returned %d.\n", *(int *)res2);

    return 0;
}

看起来同样有问题,返回值对不上。

运行结果如下:

>>> ./a.out                                                                                                                                      
Thread 2 started. will return num: 2
Thread 1 started. will return num: 1
Thread 1 returned 0.
Thread 2 returned 0.

如果需要返回的话,可以使用malloc得到一个heap上的指针:

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

#include <stdlib.h>

void* sum_func(void* args) {
    int stop_num = *(int*)args;
    int *ret_val = malloc(sizeof(int));
    for (int i = 0; i < 100; i++) {
        if (i == stop_num) {
            *ret_val = i + 1;
            pthread_exit((void*)ret_val);
        }
    }
    printf("never run here\n");
    return NULL;
}

int main() {
    pthread_t th1;
    int stop_num = 9 * 9;
    pthread_create(&th1, NULL, sum_func, (void*)&stop_num);

    int ret_stop_num = 0;
    int* p_t = &ret_stop_num;
    pthread_join(th1, (void*)&p_t);

    printf("thread ret val is %d\n", *p_t);
    free(p_t);
    return 0;
}

线程分类

线程按照其调度者

  1. 用户级线程,主要解决的是上下文切换的问题,其调度过程由用户决定
  2. 内核级线程,由内核调度机制实现

用户级线程要绑定内核级线程运行,一个进程中的内核级线程会分配到固定的时间片,用户级线程分配的时间片以内核级线程为准。

当cpu分配给线程的时间片用完后但线程没有执行完毕,此时线程会从运行状态返回到就绪状态,将cpu让给其它线程使用。

简单应用

1-5000的数组 两个线程分别计算1-2500 2501-5000 的和,然后相加

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

int array[5000];

typedef struct {
  int from;
  int to;
  int result;
}ARGS;

void* myfunc(void* args) {
    int i;
    ARGS* arg_n = (ARGS*)args;
    int from_num = arg_n->from;
    int to_num = arg_n->to;

    for (i = from_num; i < to_num; i++) {
        arg_n->result += array[i];
    }
    return NULL;
}

int main() {
    int i;
    for (i = 0; i < 5000; i++) {
        array[i] = i + 1;
    }

    ARGS arg1 = {0, 2500, 0};
    ARGS arg2 = {2500, 5000, 0};

    pthread_t thread1, thread2;

    pthread_create(&thread1, NULL, myfunc, &arg1);
    pthread_create(&thread2, NULL, myfunc, &arg2);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    printf("%d +  %d = %d \n", arg1.result, arg2.result, arg1.result + arg2.result);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值