I am new to threading, and i am trying to write a function that keep outputing an variable while i should be able to change that variable at runtime, and the output should change to my input once I input a new value in. By the following program is not running as i expected, whats wrong here? is there anything i can reference to so i can build this funciton out?
int a;
void* ptr;
void* Input(void* arg){
while(true){
std::cin >> a;
std::cout << std::endl;
}
return ptr;
}
void* Output(void *arg){
while(true){
std::cout << a << std::endl;
}
return ptr;
}
int main(){
pthread_t GetInput;
pthread_create(&GetInput,NULL,Input,NULL);
pthread_t GetOutput;
pthread_create(&GetOutput,NULL,Output,NULL);
}
CodePudding user response:
Your main thread is not waiting for your child thread and exited when main()
returned. To make your main thread to wait for children finish their jobs, you should call pthread_join()
for them.
int main(){
pthread_t GetInput;
pthread_create(&GetInput,NULL,Input,NULL);
pthread_t GetOutput;
pthread_create(&GetOutput,NULL,Output,NULL);
pthread_join(GetInput, NULL);
pthread_join(GetOutput, NULL);
return 0;
}
Here's another alternative using std::async()
for your code.
#include <chrono>
#include <future>
#include <iostream>
#include <mutex>
int a;
std::mutex mtx_;
void Input(void* arg) {
while (true) {
int tmp_a;
std::cin >> tmp_a;
{
std::lock_guard<std::mutex> lock(mtx_);
a = tmp_a;
}
std::cout << std::endl;
}
}
void Output(void* arg) {
while (true) {
{
std::lock_guard<std::mutex> lock(mtx_);
std::cout << a << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main() {
auto ft_in = std::async(std::launch::async, Input, &a);
auto ft_out = std::async(std::launch::async, Output, &a);
ft_in.wait();
ft_out.wait();
return 0;
}
CodePudding user response:
You have several fundamental problems
- Data racing between the two threads
- No exit strategy for triggering thread shutdown
- No detection method for
main
to know threads are done.
The first is addressed by introducing a cooperation between the threads that read/write the shared data between them (in this case, a
). Though heavy handed, a mutex and condition variable can be deployed for this purpose.
The second simply means your threads don't know when to quit. This is technically ok, but it means any joining on them is already known to be fruitless. For my example below I'm simply using an input value of 0
to indicate shutdown.
The third is handled by simply having main
join each thread respectively. The plan is, when the reader gets a 0
it knows it is time to shut down, but also sets up the output writer to do the same.
Doing this with the C 11 or later standard library is fairly straightforward. Note this also prints a platform dependent thread id to assist in seeing that the input and output threads are two different things:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
// predicate data
int a=0;
bool is_input = true;
std::mutex mtx;
std::condition_variable cv;
void GetInput()
{
while (true)
{
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, []() { return is_input; });
// we own the mutex (so 'a' is fair game) and we
// know 'is_input' is true or else we wouldn't
// be here; we'd still be waiting
std::cin.tie(&std::cout);
std::cout << std::this_thread::get_id() << ": ";
std::cin >> a;
// got 'a' (we hope; really should error check).
// change predicate state and notify waiter.
is_input = false;
cv.notify_one();
// leave if 'a' is zero. the output waiter will
// ultimately do the same.
if (a == 0)
break;
}
}
void GetOutput()
{
while (true)
{
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, []() { return !is_input; });
// leave when 'a' is zero
if (a == 0)
break;
// we own the mutex (so 'a' is fair game) and we
// know 'is_input' is false or else we wouldn't
// be here; we'd still be waiting
std::cout << std::this_thread::get_id() << ": " << a << '\n';
// reset the predicate and notify any waiters
is_input = true;
cv.notify_one();
}
}
int main()
{
std::thread reader{ GetInput };
std::thread writer { GetOutput };
reader.join();
writer.join();
}
Output Example
0x70000a78e000: 1
0x70000a811000: 1
0x70000a78e000: 2
0x70000a811000: 2
0x70000a78e000: 3
0x70000a811000: 3
0x70000a78e000: 4
0x70000a811000: 4
0x70000a78e000: 5
0x70000a811000: 5
0x70000a78e000: 0
Note the thread id's toggling back and forth depending on input vs output.
pthread
Implementation
Though I strongly discourage it, doing this with pthreads is possible. The equivalent code to the previous example would look like this:
#include <iostream>
#include <pthread.h>
// predicate data
int a = 0;
bool is_input = true;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
void *GetInput(void *)
{
pthread_mutex_lock(&mtx);
while (true)
{
while (!is_input)
pthread_cond_wait(&cv, &mtx);
// we own the mutex (so 'a' is fair game) and we
// know 'is_input' is true or else we wouldn't
// be here; we'd still be waiting
std::cin.tie(&std::cout);
std::cout << pthread_self() << ": ";
std::cin >> a;
// got 'a' (we hope; really should error check).
// change predicate state and notify waiter.
is_input = false;
pthread_cond_signal(&cv);
// leave if 'a' is zero. the output waiter will
// ultimately do the same.
if (a == 0)
break;
}
pthread_mutex_unlock(&mtx);
return nullptr;
}
void* GetOutput(void *)
{
pthread_mutex_lock(&mtx);
while (true)
{
while (is_input)
pthread_cond_wait(&cv, &mtx);
// leave when 'a' is zero
if (a == 0)
break;
// we own the mutex (so 'a' is fair game) and we
// know 'is_input' is false or else we wouldn't
// be here; we'd still be waiting
std::cout << pthread_self() << ": " << a << '\n';
// reset the predicate and notify any waiters
is_input = true;
pthread_cond_signal(&cv);
}
pthread_mutex_unlock(&mtx);
return nullptr;
}
int main()
{
pthread_t input;
pthread_create(&input, nullptr, &GetInput, nullptr);
pthread_t output;
pthread_create(&output, nullptr, &GetOutput, nullptr);
pthread_join(input, nullptr);
pthread_join(output, nullptr);
}
Output Example
0x700005081000: 1
0x700005104000: 1
0x700005081000: 2
0x700005104000: 2
0x700005081000: 3
0x700005104000: 3
0x700005081000: 4
0x700005104000: 4
0x700005081000: 5
0x700005104000: 5
0x700005081000: 0
Note that sending a pthread_self()
to std::cout
may not work on your platform, so buyer beware.
Finally, neither of the above examples have any reasonable error checking, but hopefully the workflow comes across, which was somewhat the point.
CodePudding user response:
Well,I don't know how to use pthread.
And it seems Mr.john-park or Ms.john-park already gave a answer.
But I think use thread is a better choice.
To use it,we should:
#include<thread>
After that,if u want to start a new thread,and "connect" it with a function(In fact,we usually do)
There is a class named thread.
First,we should
thread *thread name*(*function name*);
WARNING:function nameshould be without "(" and ")"
May because here should be a pointer.
Then,to the question.
Suppose we wrote:
thread GetInput(Input);
thread GetOutput(Output);
When u want to stop GetOutput some time and run GetInput,
just
GetInput.join()
Here's a not so good example:
#include <iostream>
#include <thread>
using namespace std;
void f1()
{
while (true)
{
cout << "THREAD 1!" << endl;
}
}
void f2()
{
for (int i = 0; i < 10; i )
cout << "THREAD 2!" << endl;
thread t1(f1);
t1.join();
for (int i = 0; i < 10; i )
cout << "THREAD 2!" << endl;
}
int main()
{
thread t2(f2);
return 0;
}
First,we started t2.
Then t2 started t1.
Now we can know why we use join().
If we don't join(),
It'll be hard for us to read the output because it'll close the cmd window quickly.
But we can know,
after t2 end,
return 0;
ran.
But if we used join()
Here's the output:
THREAD 2!
THREAD 2!
THREAD 2!
...(THREAD 2!*10)
THREAD 1!
THREAD 1!
...(Always THREAD 1!)