Linux C 编程——多线程

Linux C 编程——多线程

线程是计算机中独立运行的最小单位,运行时占用很少的系统资源。与多进程相比,多进程具有多进程不具备的一些优点,其最重要的是:对于多线程来说,其能够比多进程更加节省资源。

1、线程创建

在Linux中,新建的线程并不是在原先的进程中,而是系统通过一个系统调用clone()。该系统copy了一个和原先进程完全一样的进程,并在这个进程中执行线程函数。

在Linux中,通过函数pthread_create()函数实现线程的创建:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

其中:

  • thread表示的是一个pthread_t类型的指针;
  • attr用于指定线程的一些属性;
  • start_routine表示的是一个函数指针,该函数是线程调用函数;
  • arg表示的是传递给线程调用函数的参数。

当线程创建成功时,函数pthread_create()返回0,若返回值不为0则表示创建线程失败。对于线程的属性,则在结构体pthread_attr_t中定义。

线程创建的过程如下所示:

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

void* thread(void *id){
        pthread_t newthid;

        newthid = pthread_self();
        printf("this is a new thread, thread ID is %u\n", newthid);
        return NULL;
}

int main(){
        int num_thread = 5;
        pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread);

        printf("main thread, ID is %u\n", pthread_self());
        for (int i = 0; i < num_thread; i++){
                if (pthread_create(&pt[i], NULL, thread, NULL) != 0){
                        printf("thread create failed!\n");
                        return 1;
                }
        }
        sleep(2);
        free(pt);
        return 0;
}

在上述代码中,使用到了pthread_self()函数,该函数的作用是获取本线程的线程ID。在主函数中的sleep()用于将主进程处于等待状态,以让线程执行完成。最终的执行效果如下所示:

www.zeeklog.com  - Linux C 编程——多线程

那么,如何利用arg向子线程传递参数呢?其具体的实现如下所示:

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

void* thread(void *id){
        pthread_t newthid;

        newthid = pthread_self();
        int num = *(int *)id;
        printf("this is a new thread, thread ID is %u,id:%d\n", newthid, num);
        return NULL;
}

int main(){
        //pthread_t thid;
        int num_thread = 5;
        pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread);
        int * id = (int *)malloc(sizeof(int) * num_thread);

        printf("main thread, ID is %u\n", pthread_self());
        for (int i = 0; i < num_thread; i++){
                id[i] = i;
                if (pthread_create(&pt[i], NULL, thread, &id[i]) != 0){
                        printf("thread create failed!\n");
                        return 1;
                }
        }
        sleep(2);
        free(pt);
        free(id);
        return 0;
}

其最终的执行效果如下图所示:

www.zeeklog.com  - Linux C 编程——多线程

如果在主进程提前结束,会出现什么情况呢?如下述的代码:

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

void* thread(void *id){
        pthread_t newthid;

        newthid = pthread_self();
        int num = *(int *)id;
        printf("this is a new thread, thread ID is %u,id:%d\n", newthid, num);
        sleep(2);
        printf("thread %u is done!\n", newthid);
        return NULL;
}

int main(){
        //pthread_t thid;
        int num_thread = 5;
        pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread);
        int * id = (int *)malloc(sizeof(int) * num_thread);

        printf("main thread, ID is %u\n", pthread_self());
        for (int i = 0; i < num_thread; i++){
                id[i] = i;
                if (pthread_create(&pt[i], NULL, thread, &id[i]) != 0){
                        printf("thread create failed!\n");
                        return 1;
                }
        }
        //sleep(2);
        free(pt);
        free(id);
        return 0;
}

此时,主进程提前结束,进程会将资源回收,此时,线程都将退出执行,运行结果如下所示:

www.zeeklog.com  - Linux C 编程——多线程

2、线程挂起

在上述的实现过程中,为了使得主线程能够等待每一个子线程执行完成后再退出,使用了free()函数,在Linux的多线程中,也可以使用pthread_join()函数用于等待其他线程,函数的具体形式为:

int pthread_join(pthread_t thread, void **retval);

函数pthread_join()用来等待一个线程的结束,其调用这将被挂起。

一个线程仅允许一个线程使用pthread_join()等待它的终止。

如需要在主线程中等待每一个子线程的结束,如下述代码所示:

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

void* thread(void *id){
        pthread_t newthid;

        newthid = pthread_self();
        int num = *(int *)id;
        printf("this is a new thread, thread ID is %u,id:%d\n", newthid, num);
        free(3);
        printf("thread %u is done\n", newthid);
        return NULL;
}

int main(){
        int num_thread = 5;
        pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread);
        int * id = (int *)malloc(sizeof(int) * num_thread);

        printf("main thread, ID is %u\n", pthread_self());
        for (int i = 0; i < num_thread; i++){
                id[i] = i;
                if (pthread_create(&pt[i], NULL, thread, &id[i]) != 0){
                        printf("thread create failed!\n");
                        return 1;
                }
        }
        for (int i = 0; i < num_thread; i++){
                pthread_join(pt[i], NULL);
        }
        free(pt);
        free(id);
        return 0;
}

最终的执行效果如下所示:

www.zeeklog.com  - Linux C 编程——多线程
注:在编译的时候需要链接libpthread.a:
g++ xx.cc -lpthread -o xx

Read more

面试官:你使用过StringUtils工具类吗!!!

面试官:你使用过StringUtils工具类吗!!!

面试官:你使用过StringUtils工具类吗!!! * StringUtils类是org.apache.commons.lang3包下提供的一个常用于处理字符串的工具类。 1. 使用需要引入以下依赖 <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> </dependency> 2. 常用方法 * abbreviateMiddle:缩写字符串的中间部分。 * appendIfMissing:如果字符串不以指定后缀结尾,则追加后缀。 * capitalize:将字符串的第一个字符大写。 * center:将字符串居中对齐。 * chomp:

By Ne0inhk
Java中创建线程的多种方式。

Java中创建线程的多种方式。

在Java中,创建线程的方式有多种,包括继承Thread类、实现Runnable接口、使用Executor框架、使用Callable和Future等。 1. 继承Thread类 通过继承Thread类并重写run()方法来创建线程。 代码如下: public class MyThread extends Thread { @Override public void run() { System.out.println("Thread running: " + Thread.currentThread().getName()); } public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); } } 2.实现Runnable接口 实现Runnable接口并实现run()方法来创建线程,更灵活,可以继承其他类。 代码如下: public

By Ne0inhk
Java常用的并发工具类。

Java常用的并发工具类。

在Java中,会经常使用到一些并发工具类来处理多线程问题,从而提高系统性能,本文总结一下在开发中常用的工具类。 1. CountDownLatch java.util.concurrent.CountDownLatch允许一个或多个线程等待其他线程完成操作后再继续执行。 CountDownLatch latch = new CountDownLatch(1); // 在另一个线程中调用 latch.countDown() 来触发等待线程继续执行 latch.await(); 2. CyclicBarrier java.util.concurrent.CyclicBarrier 允许一组线程互相等待,直到所有线程都到达某个屏障点后再继续执行。 CyclicBarrier barrier = new CyclicBarrier(3); // 在不同线程中调用 barrier.await() 来等待所有线程到达屏障点 3. Semaphore java.util.concurrent.Semaphore 允许控制同时访问特定资源的线程数量,可以用来限制并

By Ne0inhk
Java——TreeMap、Properties的使用。

Java——TreeMap、Properties的使用。

TreeMap、Properties的使用 TreeMap是Java中的一个有序的Map集合类,它继承自SortedMap接口,可以根据键的自然顺序或者自定义的Comparator进行排序。Properties是一个特殊的Map集合类,它用于处理属性文件,通常用来存储配置信息。 代码如下: import java.util.*; public class MapExample { public static void main(String[] args) { // 创建一个TreeMap对象 TreeMap<String, String> treeMap = new TreeMap<>(); // 向TreeMap中添加元素 treeMap.put("name", "Alice"); treeMap.put("age", "25"); treeMap.

By Ne0inhk