Thread and Process are related to each other but they are fundamentally different.
Process : it can be thought as an instance of a program in execution. Each process is an independent entity to which system resource (CPU time, memory, etc) are allocated and each process is executed in a separate address space. One process can not access the variables and data structures of another process. If you wish to access another process's resources, inter-process communication have to be used such as pipes, files, sockets etc.
A thread use the same stack of a process. A process can have multiple threads. Multiple threads share parts of their state. Typically, one allows multiple threads to read and write the same memory. Each thread has its own registers and its own stack. But other threads can read and write the stack memory. And, a thread is a particular execution path of a process. When one thread modifies a process resource, the change is immediately visible to sibling threads.
Locks:
Synchronized Keyword: Java provides two ways to achieve synchronization: synchronized method and synchronized statement
Synchronized method: methods of a class which need to be synchronized are declared with "synchronized" keyword, if one thread is executing a synchronized method, all other threads which want to execute any of the synchronized methods to the same objects are blocked.
For example: method1 and method2 need to be synchronized
public class SynchronizedMethod {
public synchronized returnType Method1() {// statements}
public synchronized returnType Method2() {//statements}
Other methods......
}
Synchronized statement: it provides the synchronization for a group of statements rather than a method as a whole.
Optimistic Lock VS. Pessimistic Lock
Optimistic locking is a strategy where you read a record, take note of a version number (might also be date, timestamps or checksum/hashes) and check that the veresion hasn't changed before you write the record back. When you write the record back, filter the update on the version to make sure it is atomic. (hasn't update between when you check the version and write the record to the disk) and update the version in one hit. If the record is dirty(different version to you), you abort the transaction and the user can restart it. This strategy is most applicable to high-volume systems and three-tier architectures where you do not necessarily maintain a connection to the database for your session. In this situation the client cannot actually maintain databases locks as the connections are taken from the pool and you many not be using the same connection from one access to the next.
Pessimistic Locking: when you lock the record for your exclusive use until you have finished with it. It has much better integrity than optimistic locking but requires you to be careful with your application design to avoid deadlocks. To use pessimistic locking you need either a direct connection to the database or an externally available transaction ID that can be used independently of the connection.
C++ thread basics.
C++ makes multi-threads programming easier. We can include <thread> to create a thread. See following a simple "Hello Word" thread example:
#include <iostream>
#include <thread>
#include <string>
using namespace std;
int main() {
thread t([] () {cout << "Hello World!" << endl;});
t.join();
} // to compile this code, we need to specify -pthread
In the above example, when the main thread exit, no matter child thread have finished or not, all the children thread should be end. When the child thread exit, no matter normally exit or ended abnormally, thread will be end, at this time, the resource allocated hasn't been released. if we don't manually release the resource, we will lost track of the resource which makes the resource waste. There are two operations which can help this situation.
1: joinable, the main thread should wait for the child thread, only when the child thread ends, the main thread can continue the later operations.
2: detached. The parent and child threads are detached, the parent thread doesn't need to wait for the child thread's end. When child thread ends, system will reallocate the resource.
Another example to pass value by reference.
int main() {
int i = 0;
thread t([] (int& x) {cout << x++ << endl;}, ref(i));
t.join();
cout << i << endl;
}
this_thread contains several useful functions"
1: get_id : returns the current thread id.
2: yield: when this thread waits, it allows CPU to execute other threads first.
3: sleep_for: stop current thread for at least tTime
4: sleep_util: stop current thread for tTime.
Mutex
mutex is an inevitable problem. C++ provides an easy way to solve this. There are four types of mutex
1: mutex, the super mutex class which provide lock() and unlock() function
2: recursive_mutex, recursive mutex class. It allows one thread to class for the mutex multiple times. This is always used in big project will multiple department.
in this case, even if multiple people use the same lock, it will not be in the dead_lock
3: time_mutex, timed recursive mutex class, beyond mutex, it is also ok to get the lock in some time intervals. if one thread will lasts for a long time, it is good to use timing mutex.
4: recursive_time_mutex class, which is subclass timed_mutex class and recursive_mutex
#include <iostream>
#include <thread>
#include <mutex>
#include <string>
#include <vector>
using namespace std;
mutex mt;
void f() {
mt.lock();
cout << "enter critical section: " << endl;
this_thread::sleep_for(chrono::seconds(5));
cout << "leave critical section: " << endl;
mt.unlock();
}
int main() {
vector<thread> v(5);
for(auto &i : v) i = thread(f);
for(auto &i : v) i.join();
}
C++ feature provide an asynchronism way to communicate among threads. It lets function to execute by himself and when necessary, it can get the needed result. Also, it can delay the timing of throwing exceptions.
#include <iostream>
#include <future>
using namespace std;
int main()
{
future<int> f = async([]()->int { return 42; });
this_thread::sleep_for(chrono::seconds(2));
cout << "The answer to life the universe and everything is: " << f.get() << endl;
}