Linux 多线程

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hudazhe/article/details/80028225

Linux 多线程

线程概念

在一个程序里的一个执行路线就叫做线程。
每个进程都至少有一个线程。

进程和线程

进程是资源分配的基本单位。
线程是调度和执行的基本单位。
线程共享进程的数据:代码段,数据段,bss段和堆段,文件描述符,打开的库,mmap映射的文件以及共享内存空间。
线程也有自己的私有数据:线程 id, PCB,寄存器,栈,errno,信号屏蔽字,调度优先级。
资源分配情况
这里写图片描述

在 Linux下的线程被称为轻量级线程,在内核角度来看,Linux并不区分进程和线程。在创建线程时,Linux 内核仍然创建一个新的 PCB 来标识这个线程,而内核对进程/线程的认识来源于PCB,因此内核并不认为他们有区别。

线程的优点

  1. 创建一个线程的代价远小于创建一个进程的代价。
  2. 线程之间的切换需要的做的工作小于进程间的切换。
  3. 占用资源更少。
  4. 能充分多处理器可并行数量。
  5. 同进程下的线程间数据交换不需要经过 OS。

线程的缺点

  1. 性能损失
  2. 健壮性降低
  3. 缺乏访问控制
  4. 编程难度提高

线程操作

创建线程

pthread_create()函数

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *),
                   void *arg);
第一个参数 用来存储线程 ID
第二个参数 用来设置线程属性 一般情况填NULL
第三个参数 线程运行的代码的起始地址
第四个参数 运行函数的参数地址           

这里写图片描述

这里写图片描述
在这里会发现,我们创建的线程并没有打印出我们想要的数据,这是因为,在多线程编程中,主线程退出其他的子线程也会退出,所以我们创建的线程还未运行完就已经结束了,这里我们可以让主线程睡眠1s。
这里写图片描述
这里写图片描述

线程等待与退出

线程退出

线程退出的几种情况:
1. 调用 pthread_eixt 函数退出
2. 其他线程调用 pthread_cancel 函数取消该线程,且该线程可以被取消。
3. 创建线程的进程退出或整个函数结束。
4. 其中的一个线程执行了 exec 类函数执行新的代码 ,替换当前进程所有地址空间。
5. 当前线程代码执行完毕。

pthread_exit()函数

void pthread_exit(void *retval);
结束一个线程,参数为线程退出状态。

线程等待

一般情况下,为了有效同步子线程,在主线程中都将等待子线程结束,使用 pthread_join() 函数显示的等待线程结束。

int pthread_join(pthread_t th, void **retval);
第一个参数为 被等待的线程 ID
第二个参数为 线程退出状态
此线程必须同调用它的进程相关联,称为关联线程

如果要设置某个线程为独立线程,则可以调用pthread_detach()函数

int pthread_detach(pthread_t th);

线程退出前的操作:
不论是可预见的线程终止还是异常终止,都会存在资源释放的问题,在不存在因运行而出错而退出的前提下,如何保证线程终止时能顺利的释放掉自己所占用的资源,是一个需要解决的问题。
pthread_cleanup_push()/pthread_cleanup_pop()函数用于自动释放资源,可以自己了解一下。

展开阅读全文

Linux 多线程函数解析

05-16

Linux多线程函数解析rnLinux多线程函数用得比较多的是下面的3个rnpthread_create(),pthread_exit(),pthread_join();它们都是在头文件之中。编译时需要加静态库-lpthreadrnrn下面是函数的说明:rn  pthread_create是UNIX环境创建线程函数rnint pthread_create(rnpthread_t *restrict tidp,rnconst pthread_attr_t *restrict_attr,rnvoid*(*start_rtn)(void*),rnvoid *restrict arg);rn返回值rn  若成功则返回0,否则返回出错编号rn  返回成功时,由tidp指向的内存单元被设置为新创建线程的线程ID。attr参数用于制定各种不同的线程属性。新创建的线程从start_rtn函数的地址开始运行,该函数只有一个万能指针参数arg,如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg的参数传入。rn  linux下用C开发多线程程序,Linux系统下的多线程遵循POSIX线程接口,称为pthread。rn  由 restrict 修饰的指针是最初唯一对指针所指向的对象进行存取的方法,仅当第二个指针基于第一个时,才能对对象进行存取。对对象的存取都限定于基于由 restrict 修饰的指针表达式中。 由 restrict 修饰的指针主要用于函数形参,或指向由 malloc() 分配的内存空间。restrict 数据类型不改变程序的语义。 编译器能通过作出 restrict 修饰的指针是存取对象的唯一方法的假设,更好地优化某些类型的例程。rn参数rn  第一个参数为指向线程标识符的指针。rn  第二个参数用来设置线程属性。rn  第三个参数是线程运行函数的起始地址。rn  最后一个参数是运行函数的参数。rn另外,在编译时注意加上-lpthread参数,以调用静态链接库。因为pthread并非Linux系统的默认库rnrnpthread_exit(void* retval);rn线程通过调用pthread_exit函数终止自身执行,就如同进程在结束时调用exit函数一样。这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针。该指针可以通过pthread_join(pthread_t tpid, void **value_ptr)中的第二个参数value_ptr获取到。rnrn函数pthread_join用来等待一个线程的结束。函数原型为:rn  extern int pthread_join __P (pthread_t __th, void **__thread_return);rn第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程退出时的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。如果执行成功,将返回0,如果失败则返回一个错误号。rn所有线程都有一个线程号,也就是Thread ID。其类型为pthread_t。通过调用pthread_self()函数可以获得自身的线程号。rnrn下面是一个简单的例子,子线程thread_fun会打出5次“this is thread_fun print!”然后调用pthread_exit退出,并返回一个指向字符串“this is thread return value!”的指针。在主函数里面调用pthread_join等待thread_fun线程结束,然后读取子线程的返回值到value中,再打印出来。rn输出结果是:rnpthread_create ok!rnthis is thread_fun print!rnthis is thread_fun print!rnthis is thread_fun print!rnthis is thread_fun print!rnthis is thread_fun print!rnpthread exit value: this is thread return value!rnrn01.#includern02.#includern03.#includern04.#includern05.#includern06.#includern07.//////////////////////////////////////////////////////rn08.void *thread_fun(void *arg) rn09. int i=0;rn10. char *value_ptr = "this is thread return value!\n";rn11. for (i=0; i<5; i++) rn12. printf("this is thread_fun print!\n");rn13. sleep(1);rn14. rn15. pthread_exit((void*)value_ptr);rn16.rn17.//////////////////////////////////////////////////////rn18.int main(int argc, char **argv) rn19. pthread_t pid;rn20. int ret;rn21. void* value;rn22.rn23. ret = pthread_create(&pid, NULL, thread_fun, NULL);rn24. if (ret) rn25. printf("pthread_create failed!\nerrno:%d\n", errno);rn26. return -1;rn27. rn28. printf("pthread_create ok!\n");rn29.rn30. pthread_join(pid, &value);rn31. printf("pthread exit value: %s\n", value);rn32. return 0;rn33.rn34.rn35.rnrn 论坛

linux 多线程问题

04-12

大家好:rn 我在移植socket服务程序的时候遇见了这个问题,就是我创建了多个子线程。但是我把子线程退出就会出现主线程和所有子线程同时退出。我在我自己的电脑上面用ubuntu运行了没有这个问题。我移植到我的平台上面就出现这个问题了。这个是源代码rn#include // for printfrn#include // for exitrn#include // for bzerorn#include rn#include rn#include // for sockaddr_inrn#include // for socketrn#include // for socketrn#include rn#include rnrn#define SERVER_PORT 8090rn#define LISTEN_QUEUE_LENGTH 20rn#define BUFFER_SIZE 1024rn#define MAX_THREAD_NUM 100rnrnint thread_count = 0;rnpthread_t threads[MAX_THREAD_NUM];rnrn/**rn * rn * @param conn_socketrn */rnvoid recv_data(int conn_socket);rnrnrn/*rn * rn */rnint main(int argc, char** argv)rnrn // œšÁ¢Socketrn int server_socket = socket(PF_INET, SOCK_STREAM, 0);rn if (server_socket < 0) rn printf("Socket create failed.\n");rn return EXIT_FAILURE;rn rnrn rn int opt = 1;rn setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));rn rnrn rn struct sockaddr_in server_addr;rn bzero(&server_addr, sizeof (server_addr));rnrn server_addr.sin_family = AF_INET;rn server_addr.sin_addr.s_addr = htons(INADDR_ANY);rn server_addr.sin_port = htons(SERVER_PORT);rn rn if (bind(server_socket, (struct sockaddr*) &server_addr, sizeof (server_addr)))rn rn printf("Bind port %d failed.\n", SERVER_PORT);rn return EXIT_FAILURE;rn rn rnrn if (listen(server_socket, LISTEN_QUEUE_LENGTH))rn rn printf("Server Listen Failed!");rn return EXIT_FAILURE;rn rn rnrn bzero(&threads, sizeof(pthread_t) * MAX_THREAD_NUM);rn while (1)rn rn struct sockaddr_in client_addr;rn socklen_t length = sizeof(client_addr);rn printf("Server Recieve accept\n");rn rn int client_conn = accept(server_socket, (struct sockaddr*) &client_addr, &length);rn if (client_conn < 0)rn rn printf("Server Accept Failed!\n");rn return EXIT_FAILURE;rn rn rn rn int pthread_err = pthread_create(threads + (thread_count++), NULL, (void *)recv_data, (void *)client_conn);rn if (pthread_err != 0)rn rn printf("Create thread Failed!\n");rn return EXIT_FAILURE;rn rn pthread_join(threads + thread_count,NULL);rn rn rn close(server_socket);rn return (EXIT_SUCCESS);rnrnrnvoid recv_data(int conn_socket)rnrn char buffer[BUFFER_SIZE];rn bzero(buffer, BUFFER_SIZE);rnrn int length = 0;rn while (length = recv(conn_socket, buffer, BUFFER_SIZE, 0))rn rn if (length < 0)rn rn printf("Server Recieve Data Failed! code %d\n", length);rn rn printf("Server Recieve Data%s\n", buffer);rn bzero(buffer, BUFFER_SIZE);rn rn close(conn_socket);rn 论坛

Linux多线程的问题

08-02

#includern#includern#includern//#includern//#includernrnint g_Flag = 0;rnrnstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;rnstatic pthread_cond_t cond = PTHREAD_COND_INITIALIZER;rnrnvoid * thread1(void *);rnvoid * thread2(void *);rnrnint main()rnrn pthread_t * tid1;rn pthread_t * tid2;rn// int rc1=0;rn// int rc2=0;rnrn printf("main thread\n");rnrn pthread_create(tid2, NULL, thread2, NULL);rn// rc2=pthread_create(tid2, NULL, thread2, NULL);rn// if(rc2 != 0)rn// printf("%s:%d\n",__func__,strerror(rc2));rnrn pthread_create(tid1, NULL, thread1, tid2);rn// rc1=pthread_create(tid1, NULL, thread1, tid2);rn// if(rc1 != 0)rn// printf("%s:%d\n",__func__,strerror(rc1));rn pthread_cond_wait(&cond,&mutex);rnrn printf("main thread exit\n");rn exit(0);rnrnrnvoid * thread1(void * arg)rnrnrn printf("this is thread1\n");rn pthread_mutex_lock(&mutex);rn if(g_Flag ==2)rn pthread_cond_signal(&cond);rn g_Flag = 1;rn pthread_mutex_unlock(&mutex);rn pthread_join(*(pthread_t*)arg,NULL);rn pthread_exit(0);rnrnrnvoid * thread2(void * arg)rnrn printf("this is thread2\n");rn pthread_mutex_lock(&mutex);rn if(g_Flag ==1)rn pthread_cond_signal(&cond);rn g_Flag = 2;rn pthread_mutex_unlock(&mutex);rn pthread_exit(0);rnrnrn这段代码编译过了,但是执行的时候会出错,在第一个创建线程的时候就segment fault了。rn但是,如果把rnint rc1 = 0;rnint rc2 = 0;rn这两句加上,程序就能正常执行。rn不明白这其中的问题,求解答rn 论坛

没有更多推荐了,返回首页