[Disclaimer: All Rights Reserved. You are welcome to reprint it. Do not use it for commercial purposes. Contact Email: feixiaoxing @ 163.com]
Multi-threaded programming is an important part of modern software technology. To understand multithreading, is multi-process involved? Of course, to learn about multi-process, it involves the operating system. Don't be nervous, though. Listen to me. The process is not complex.
(1) ticketCPUMultithreading
Before a multi-core CPU is available, our computing resources are unique. If there are multiple tasks to be processed in the system, these tasks need to be scheduled in sequence according to certain rules. What are the rules? It can be some simple scheduling methods, such
1) scheduling by priority
2) FIFO Scheduling
3) time slice scheduling and so on
Of course, in addition to CPU resources, some other resources in the system need to be shared, such as memory, files, ports, and sockets. Since the resources in the system are limited, what is the smallest unit for obtaining these resources? It is actually a process.
For example, in Linux, every resource-sharing entity is called task_struct, which is actually the same as what we call a process. Let's take a look at what content task_struct (Linux 0.11 code) includes,
struct task_struct {/* these are hardcoded - don't touch */long state;/* -1 unrunnable, 0 runnable, >0 stopped */long counter;long priority;long signal;struct sigaction sigaction[32];long blocked;/* bitmap of masked signals *//* various fields */int exit_code;unsigned long start_code,end_code,end_data,brk,start_stack;long pid,father,pgrp,session,leader;unsigned short uid,euid,suid;unsigned short gid,egid,sgid;long alarm;long utime,stime,cutime,cstime,start_time;unsigned short used_math;/* file system info */int tty;/* -1 if no tty, so it must be signed */unsigned short umask;struct m_inode * pwd;struct m_inode * root;struct m_inode * executable;unsigned long close_on_exec;struct file * filp[NR_OPEN];/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */struct desc_struct ldt[3];/* tss for this task */struct tss_struct tss;};
Each task has its own PID. In the system, resources are allocated according to the PID. This shows that the process is indeed the subject of resource allocation.
At this time, some may ask, since task_struct is the subject of resource allocation, why thread? Why is the system scheduled by thread instead of by process? The reason is actually very simple, and data communication between processes is very troublesome, because we want to separate these processes not to affect each other.
Assume that data is transmitted between two processes. What are the steps required to access Shared data,
1) create shared memory
2) access Shared Memory-> System Call-> Read data
3) write to shared memory-> System Call-> write data
If you write a code, you may understand it better,
#include <unistd.h>#include <stdio.h>int value = 10;int main(int argc, char* argv[]){ int pid = fork(); if(!pid){ Value = 12; return 0; } printf("value = %d\n", value); return 1;}
The above code is a code used to create a sub-process. We found that the printed value is still 10. Although a sub-process is created in the middle and the value is modified, we find that the printed value has not changed, which means that the memory of different processes is not shared.
So what are the advantages of modifying to a thread? In fact, the biggest benefit is that each thread can not only enjoy the opportunity of independent CPU scheduling, but also share all resources under each process. If the scheduling unit is a process, each process can only do one thing, but data between processes must be interacted with each other, and data between processes must be called by the system before application, this reduces the data processing efficiency.
(2) multi-coreCPUMultithreading
Before the emergence of multiple cores, our CPU actually schedules threads in sequence according to certain rules. At a specific time point, the CPU still executes a specific thread. However, now with a multi-core CPU, everything is different, because at some point in time it is likely that N tasks run on N cores. We can write a simple open MP test. If it is still a core, the running time should be the same.
#include <omp.h>#define MAX_VALUE 10000000double _test(int value){int index;double result;result = 0.0;for(index = value + 1; index < MAX_VALUE; index +=2 )result += 1.0 / index;return result;}void test(){int index;int time1;int time2;double value1,value2;double result[2]; time1 = 0;time2 = 0;value1 = 0.0;time1 = GetTickCount();for(index = 1; index < MAX_VALUE; index ++)value1 += 1.0 / index;time1 = GetTickCount() - time1;value2 = 0.0;memset(result , 0, sizeof(double) * 2);time2 = GetTickCount();#pragma omp parallel forfor(index = 0; index < 2; index++)result[index] = _test(index);value2 = result[0] + result[1];time2 = GetTickCount() - time2;printf("time1 = %d,time2 = %d\n",time1,time2);return;}
(3) multi-thread programming
Why do we need multi-threaded programming? There are many reasons for this. We can give an example to solve this problem.
1) Some are to improve the running speed, such as multithreading under multi-core CPU.
2) some of them are to improve resource utilization. For example, when downloading resources in a network environment, the latency is often high. We can obtain resources from different places through different threads, which improves the efficiency.
3) Some provide better services, such as servers.
4) Other places that require multi-threaded programming