I am trying to understand how semaphores work in C++ but I am having some troubles.
Here is my code:
#include <iostream>
#include <pthread.h>
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <semaphore.h>
using namespace std;
static sem_t *sem_thread;
static pthread_t thread_id;
void * threadFunc(void *) {
cout << "threadFunc\n";
cout << "threadFunc\n";
cout << "threadFunc\n";
cout << "threadFunc\n";
cout << "threadFunc\n";
sem_post(sem_thread);
return 0;
}
int main()
{
// Init semaphores
sem_thread = sem_open("./semaphores/sem_thread", O_TRUNC, 0777, 0);
// Init thread
int rc = pthread_create(&thread_id, NULL, threadFunc, NULL);
if (rc != 0)
{
cerr << "Pthread couldn't be created. rc=" << rc << endl;
abort();
}
sem_wait(sem_thread);
cout << "Main thread\n";
cout << "Main thread\n";
cout << "Main thread\n";
cout << "Main thread\n";
cout << "Main thread\n";
sem_close(sem_thread);
sem_unlink("./semaphores/sem_thread");
return 0;
}
So I expect the program to print threadFunc first and then Main thread. However, this is what I get:
Main thread
tMhariena dtFhurneca
dt
hMraeiand Ftuhnrce
atdh
rMeaaidnF utnhcr
etahdr
eMaadiFnu ntch
rteharde
adFunc
Any idea of what's happening?
You're not creating the semaphore, nor checking whether it was created.
There are two problems with your call to sem_open:
you need O_CREAT, not O_TRUNC, to create it.
the name isn't valid. Named semaphores aren't kept in the filesystem.
Looking at man sem_overview, the naming convention is specified thusly:
A named semaphore is identified by a name of the form /somename;
that is, a null-terminated string of up to NAME_MAX-4 (i.e.,
251) characters consisting of an initial slash, followed by one
or more characters, none of which are slashes.
Related
I need your help. Program A executes program B with fork(). Every 5 seconds the process belonging to program B is interrupted. If the user enters any key within a certain time, the process is continued and interrupted again after the same time interval. If no key is entered, both program A and program B are terminated prematurely. I have tried the following code, but it does not work. Any suggestions/tips that will help me?
#include <iostream>
#include <chrono>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
using namespace std;
using namespace chrono;
int pid;
void signal_handler(int signum) {
cout << "Programm B is interrupted. Please enter any key within 5 or the programm will be terminated" << endl;
kill(pid,SIGSTOP);
alarm(5);
pause();
alarm(5);
}
int main(int argc, char* argv[]) {
//Usage
if(string(argv[1]) == "h" || string(argv[1]) == "help"){
cout << "usage" << endl;
return 0;
}
signal(SIGALRM, signal_handler);
pid = fork();
if (pid == 0) {
cout << "Name of programm B: " << argv[1] << endl;
cout << "PID of programm B: " << getpid() << endl;
execvp(argv[1], &argv[1]);
} else if (pid > 0) {
cout << "PID of programm A: " << getpid() << endl;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
waitpid(pid, nullptr, 0);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(t2 - t1).count();
cout << "Computing time: " << duration << "ms" << endl;
} else {
cerr << "error << endl;
return 1;
}
return 0;
}
Any help or sulution. I am a beginner in c++ btw.
Signals can get tricky and there are lots of issues with your approach.
You should:
kick off the timer (alarm(5)) in main
do the sighandler registration and timer kick-off after you've spawned the child (or you somewhat risk running the signal handler in the child in between fork and execvp)
use sigaction rather than signal to register the signal, as the former has clear portable semantics unlike the latter
loop on EINTR around waitpid (as signal interruptions will cause waitpid to fail with EINTR)
As for the handler, it'll need to
use only async-signal-safe functions
register another alarm() around read
unblock SIGALRM for the alarm around read but not before you somehow mark yourself as being in your SIGALRM signal handler already so the potential recursive entry of the handler can do a different thing (kill the child and exit)
(For the last point, you could do without signal-unblocking if you register the handler with .sa_flags = SA_NODEFER, but that has the downside of opening up your application to stack-overflow caused by many externally sent (via kill) SIGALRMs. If you wanted to handle externally sent SIGALRMs precisely, you could register the handler with .sa_flags=SA_SIGINFO and use info->si_code to differentiate between user-sends and alarm-sends of SIGALRM, presumably aborting on externally-sent ones)
It could look something like this (based on your code):
#include <iostream>
#include <chrono>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
//AS-safe raw io helper functions
ssize_t /* Write "n" bytes to a descriptor */
writen(int fd, const char *ptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
nleft = n;
while (nleft > 0) {
if ((nwritten = write(fd, ptr, nleft)) < 0) {
if (nleft == n)
return(-1); /* error, return -1 */
else
break; /* error, return amount written so far */
} else if (nwritten == 0) {
break;
}
nleft -= nwritten;
ptr += nwritten;
}
return(n - nleft); /* return >= 0 */
}
ssize_t writes(int fd, char const *str0) { return writen(fd,str0,strlen(str0)); }
ssize_t writes2(char const *str0) { return writes(2,str0); }
//AS-safe sigprockmask helpers (they're in libc too, but not specified as AS-safe)
int sigrelse(int sig){
sigset_t set; sigemptyset(&set); sigaddset(&set,sig);
return sigprocmask(SIG_UNBLOCK,&set,0);
}
int sighold(int sig){
sigset_t set; sigemptyset(&set); sigaddset(&set,sig);
return sigprocmask(SIG_BLOCK,&set,0);
}
#define INTERRUPT_TIME 5
using namespace std;
using namespace chrono;
int pid;
volatile sig_atomic_t recursing_handler_eh; //to differentiate recursive executions of signal_handler
void signal_handler(int signum) {
char ch;
if(!recursing_handler_eh){
kill(pid,SIGSTOP);
writes2("Programm B is interrupted. Please type enter within 5 seconds or the programm will be terminated\n");
alarm(5);
recursing_handler_eh = 1;
sigrelse(SIGALRM);
if (1!=read(0,&ch,1)) signal_handler(signum);
alarm(0);
sighold(SIGALRM);
writes2("Continuing");
kill(pid,SIGCONT);
recursing_handler_eh=0;
alarm(INTERRUPT_TIME);
return;
}
kill(pid,SIGTERM);
_exit(1);
}
int main(int argc, char* argv[]) {
//Usage
if(string(argv[1]) == "h" || string(argv[1]) == "help"){
cout << "usage" << endl;
return 0;
}
pid = fork();
if (pid == 0) {
cout << "Name of programm B: " << argv[1] << endl;
cout << "PID of programm B: " << getpid() << endl;
execvp(argv[1], &argv[1]);
} else if (pid < 0) { cerr << "error" <<endl; return 1; }
struct sigaction sa; sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags=0; sigaction(SIGALRM, &sa,0);
//signal(SIGALRM, signal_handler);
alarm(INTERRUPT_TIME);
cout << "PID of programm A: " << getpid() << endl;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
int r;
do r = waitpid(pid, nullptr, 0); while(r==-1 && errno==EINTR);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(t2 - t1).count();
cout << "Computing time: " << duration << "ms" << endl;
return 0;
}
Not that the above will wait only for an enter key. To wait for any key, you'll need to put your terminal in raw/cbreak mode and restore the previous settings on exit (ideally on signal deaths too).
I am currently trying to learn POSIX threads and made the simple code that you can see below.
I have been told that it is bad to pass an ID to a thread as you can see I did in this code snippet:
int ID0= 0;
int ID1 = 1;
pthread_create(&thread_zero, NULL, thread_function, (void*)&ID0);
pthread_create(&thread_one, NULL, thread_function, (void*)&ID1);
Why is that?
Also, would it be better to use pthread_self?
The full code:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
void *thread_function(void *arg)
{
for(int i =0; i<=10;i++)
{
std::cout << "Hello # " << i<< " From thread : " <<*((int*)arg) << std::endl;
sleep(1);
}
std::cout <<"Thread "<<*((int*)arg)<< " terminates" << std::endl;
pthread_exit(NULL);
}
int main(){
pthread_t thread_zero;
pthread_t thread_one;
int ID0= 0;
int ID1 = 1;
pthread_create(&thread_zero, NULL, thread_function, (void*)&ID0);
pthread_create(&thread_one, NULL, thread_function, (void*)&ID1);
std::cout << "main: Creating threads" << std::endl;
std::cout << "main: Wating for threads to finish" << std::endl;
pthread_join(thread_zero, NULL);
pthread_join(thread_one, NULL);
std::cout<<"Main: Exiting"<<std::endl;
return 0;
}
Why is that?
There is nothing wrong with your code, so long as you ensure that the ID0 and ID1 do not go out of scope before you join your threads, and that either thread does not modify ID0 and ID1 without proper synchronization.
In general, when passing an entity into thread that is not larger than (void*), it is safer to pass it by value, like so:
pthread_create(&tid, NULL, fn, (void*)ID0);
When done that way, ID0 can go out of scope with no danger that the new thread will access dangling stack, and no danger of a data race (which is undefined behavior).
I am struggling with process creation and piping the child process' output into a string of the parent process. I got it working on Windows (using CreatePipe and CreateProcess and ReadFile), but can't seem to get the exact analog on Unix to work. This is my code:
#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
int exit_code;
int cout_pipe[2];
int cerr_pipe[2];
posix_spawn_file_actions_t action;
if(pipe(cout_pipe) || pipe(cerr_pipe))
cout << "pipe returned an error.\n";
posix_spawn_file_actions_init(&action);
posix_spawn_file_actions_addclose(&action, cout_pipe[0]);
posix_spawn_file_actions_addclose(&action, cerr_pipe[0]);
posix_spawn_file_actions_adddup2(&action, cout_pipe[1], 1);
posix_spawn_file_actions_adddup2(&action, cerr_pipe[1], 2);
posix_spawn_file_actions_addclose(&action, cout_pipe[1]);
posix_spawn_file_actions_addclose(&action, cerr_pipe[1]);
vector<string> argmem = {"bla"};
vector<char*> args = {&argmem[0][0], nullptr}; // I don't want to call new.
pid_t pid;
if(posix_spawnp(&pid, "echo", &action, NULL, &args[0], NULL) != 0)
cout << "posix_spawnp failed with error: " << strerror(errno) << "\n";
//close(cout_pipe[0]);
//close(cerr_pipe[0]);
close(cout_pipe[1]);
close(cerr_pipe[1]);
waitpid(pid,&exit_code,0);
cout << "exit code: " << exit_code << "\n";
// Read from pipes
const size_t buffer_size = 1024;
string buffer;
buffer.resize(buffer_size);
ssize_t bytes_read = read(cout_pipe[0], &buffer[0], buffer_size);
while ((bytes_read = read(cout_pipe[0], &buffer[0], buffer_size)) > 0)
{
cout << "read " << bytes_read << " bytes from stdout.\n";
cout << buffer.substr(0, static_cast<size_t>(bytes_read)+1) << "\n";
bytes_read = read(cout_pipe[0], &buffer[0], buffer_size);
}
if(bytes_read == -1)
cout << "Failure reading from stdout pipe.\n";
while ((bytes_read = read(cerr_pipe[0], &buffer[0], buffer_size)) > 0)
{
cout << "read " << bytes_read << " bytes from stderr.\n";
cout << buffer.substr(0, static_cast<size_t>(bytes_read)+1) << "\n";
bytes_read = read(cout_pipe[0], &buffer[0], buffer_size);
}
if(bytes_read == -1)
cout << "Failure reading from stderr pipe.\n";
posix_spawn_file_actions_destroy(&action);
}
The output is:
exit code: 0
So I suppose everything is working except the actual piping. What is wrong here? I also wonder if there is a way to read the piped bytes in a waitpid loop, but when I try that, the parent process hangs infinitely.
posix_spawn is interesting and useful, which makes this question worth necromancing -- even if it is no longer relevant to the OP.
There are some significant bugs in the code as posted. I suspect that some of these were the result of hacking in desperation, but I don't know which was the original bug:
The args array does not include the argv[0] that would represent the executable name. This results in the echo program never seeing the intended argv[1] ("bla").
The read() function is called from different places in a way that just doesn't make sense. A correct way to do this would be to only call read as part of the control expression for the while loops.
waitpid() is called before reading from the pipes. This prevents the I/O from completing (in non-trivial cases at least).
A more subtle issue with this code is that attempts to read all of the child's stdout before reading anything from stderr. In principle, this could cause the child to block while attempting to write to stderr, thus preventing the program from completing. Creating an efficient solution to this is more complicated as it requires that you can read from whichever pipe has available data. I used poll() for this. Another approach would be to use multiple threads.
Additionally, I have used sh (the command shell, i.e. bash) as the child process. This provides a great deal of additional flexibility, such as running a pipeline instead of a single executable. In particular, though, using sh provides the simple convenience of not having to manage the parsing of the command-line.
/*BINFMTCXX: -std=c++11 -Wall -Werror
*/
#include <spawn.h> // see manpages-posix-dev
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
int exit_code;
int cout_pipe[2];
int cerr_pipe[2];
posix_spawn_file_actions_t action;
if(pipe(cout_pipe) || pipe(cerr_pipe))
cout << "pipe returned an error.\n";
posix_spawn_file_actions_init(&action);
posix_spawn_file_actions_addclose(&action, cout_pipe[0]);
posix_spawn_file_actions_addclose(&action, cerr_pipe[0]);
posix_spawn_file_actions_adddup2(&action, cout_pipe[1], 1);
posix_spawn_file_actions_adddup2(&action, cerr_pipe[1], 2);
posix_spawn_file_actions_addclose(&action, cout_pipe[1]);
posix_spawn_file_actions_addclose(&action, cerr_pipe[1]);
//string command = "echo bla"; // example #1
string command = "pgmcrater -width 64 -height 9 |pgmtopbm |pnmtoplainpnm";
string argsmem[] = {"sh","-c"}; // allows non-const access to literals
char * args[] = {&argsmem[0][0],&argsmem[1][0],&command[0],nullptr};
pid_t pid;
if(posix_spawnp(&pid, args[0], &action, NULL, &args[0], NULL) != 0)
cout << "posix_spawnp failed with error: " << strerror(errno) << "\n";
close(cout_pipe[1]), close(cerr_pipe[1]); // close child-side of pipes
// Read from pipes
string buffer(1024,' ');
std::vector<pollfd> plist = { {cout_pipe[0],POLLIN}, {cerr_pipe[0],POLLIN} };
for ( int rval; (rval=poll(&plist[0],plist.size(),/*timeout*/-1))>0; ) {
if ( plist[0].revents&POLLIN) {
int bytes_read = read(cout_pipe[0], &buffer[0], buffer.length());
cout << "read " << bytes_read << " bytes from stdout.\n";
cout << buffer.substr(0, static_cast<size_t>(bytes_read)) << "\n";
}
else if ( plist[1].revents&POLLIN ) {
int bytes_read = read(cerr_pipe[0], &buffer[0], buffer.length());
cout << "read " << bytes_read << " bytes from stderr.\n";
cout << buffer.substr(0, static_cast<size_t>(bytes_read)) << "\n";
}
else break; // nothing left to read
}
waitpid(pid,&exit_code,0);
cout << "exit code: " << exit_code << "\n";
posix_spawn_file_actions_destroy(&action);
}
It seems to be platform related (works with Ubuntu 12.04 on my laptop, doesn't work with another Ubuntu 12.04 on my workstation).
This is a sample code about what I am doing with two threads.
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
#include <GL/glfw.h>
using namespace std;
int main() {
atomic_bool g_run(true);
string s;
thread t([&]() {
cout << "init" << endl;
if (!glfwInit()) {
cerr << "Failed to initialize GLFW." << endl;
abort();
}
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 2);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 1);
if(!glfwOpenWindow(640, 480, 8, 8, 8, 0, 24, 0, GLFW_WINDOW)) {
glfwTerminate();
cerr << "Cannot open OpenGL 2.1 render context." << endl;
abort();
}
cout << "inited" << endl;
while (g_run) {
// rendering something
cout << "render" << endl;
this_thread::sleep_for(chrono::seconds(1));
}
// unload glfw
glfwTerminate();
cout << "quit" << endl;
});
__sync_synchronize(); // a barrier added as ildjarn suggested.
while (g_run) {
cin >> s;
cout << "user input: " << s << endl;
if (s == "q") {
g_run = false;
cout << "user interrupt" << endl;
cout.flush();
}
}
__sync_synchronize(); // another barrier
t.join();
}
Here is my compile parameters:
g++ -std=c++0x -o main main.cc -lpthread -lglfw
My laptop run this program, like this:
init
inited
render
render
q
user input: q
user interrupt
quit
And workstation just outputs:
init
inited
render
render
q
render
q
render
q
render
^C
It just simply ignored my inputs (another program same procedure with glew and glfw, just jump out of the while loop in main thread, without reading my inputs.) BUT this thing works normally with gdb!
any idea of what's going on?
Update
After more tests on other machines, NVIDIA's driver caused this. Same thing happens on other machines with NVIDIA graphics card.
I used this code to close my program and get my q key when its runing
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <termios.h>
static struct termios old, _new;
static void * breakonret(void *instance);
/* Initialize _new terminal i/o settings */
void initTermios(int echo)
{
tcgetattr(0, &old); /* grab old terminal i/o settings */
_new = old; /* make _new settings same as old settings */
_new.c_lflag &= ~ICANON; /* disable buffered i/o */
_new.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
tcsetattr(0, TCSANOW, &_new); /* use these _new terminal i/o settings now */
}
/* Read 1 character with echo */
char getche(void)
{
char ch;
initTermios(1);
ch = getchar();
tcsetattr(0, TCSANOW, &old);
return ch;
}
int main(){
pthread_t mthread;
pthread_create(&mthread, NULL, breakonret, NULL); //initialize break on return
while(1){
printf("Data on screen\n");
sleep(1);
}
pthread_join(mthread, NULL);
}
static void * breakonret(void *instance){// you need to press q and return to close it
char c;
c = getche();
printf("\nyou pressed %c \n", c);
if(c=='q')exit(0);
fflush(stdout);
}
With this you have a thread reading the data from your keyboard
After more tests on other machines, NVIDIA's driver caused this. Same thing happens on other machines with NVIDIA graphics card.
To fix this problem, there is something to be done with the initialization order. On nvidia machines glfw has to be initialized before anything (eg. create thread, even though you are not using glfw's threading routine.) The initialization has to be complete, say, create the output window after glfwInit(), otherwise the problem persists.
Here is the fixed code.
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
#include <GL/glfw.h>
using namespace std;
int main() {
atomic_bool g_run(true);
string s;
cout << "init" << endl;
if (!glfwInit()) {
cerr << "Failed to initialize GLFW." << endl;
abort();
}
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 2);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 1);
if(!glfwOpenWindow(640, 480, 8, 8, 8, 0, 24, 0, GLFW_WINDOW)) {
glfwTerminate();
cerr << "Cannot open OpenGL 2.1 render context." << endl;
abort();
}
cout << "inited" << endl;
thread t([&]() {
while (g_run) {
cin >> s;
cout << "user input: " << s << endl;
if (s == "q") {
g_run = false;
cout << "user interrupt" << endl;
cout.flush();
}
}
});
while (g_run) {
// rendering something
cout << "render" << endl;
this_thread::sleep_for(chrono::seconds(1));
}
t.join();
// unload glfw
glfwTerminate();
cout << "quit" << endl;
}
Thanks all your helps.
I've read about synchronized thread in Posix threads tutorial. They say that function pthread_join is used for waiting thread until it stops. But why doesn't this idea work in that case?
Here is my code:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int a[5];
void* thread(void *params)
{
cout << "Hello, thread!" << endl;
cout << "How are you, thread? " << endl;
cout << "I'm glad to see you, thread! " << endl;
}
void* thread2(void *params)
{
cout << "Hello, second thread!" << endl;
cout << "How are you, second thread? " << endl;
cout << "I'm glad to see you, second thread! " << endl;
// for (;;);
}
int main()
{
pthread_t pt1, pt2;
int iret = pthread_create(&pt1, NULL, thread, NULL);
int iret2 = pthread_create(&pt2, NULL, thread2, NULL);
cout << "Hello, world!" << endl;
pthread_join(pt1, NULL);
cout << "Hello, middle!" << endl;
pthread_join(pt2, NULL);
cout << "The END" << endl;
return 0;
}
Threads are executed asynchronously, as someone already mentioned in answer to question you linked. Thread execution starts right after you create() it. So, at this point:
int iret = pthread_create(&pt1, NULL, thread, NULL);
thread() is already executing in another thread, possibly on another core (but it doesn't really matter). If you add a for (;;); in your main() right after that, you will still see thread message being printed to console.
You also misunderstood what join() does. It waits for thread termination; as your threads don't do any real work, they will (most probably) reach their ends and terminate way before you call join() on them. Once again: join() doesn't start execution of thread in given place, but waits for it to terminate (or just returns, if it's already terminated).