I have following piece of code :
// temp.h
#include <iostream>
#include <pthread.h>
static pthread_spinlock_t mylock;
__attribute__((constructor))
void init_lock() {
if(pthread_spin_init(&my_lock,0) != 0) {
// hard exit !!
exit(1);
}
}
__attribute__((destructor))
void uninit_lock() {
if(pthread_spin_destroy(&my_lock) != 0) {
// hard exit !!
exit(1);
}
}
#define EXPAND_VAR(ARG1, ARG2) \
do {\
assert(pthread_spin_lock(&my_lock) == 0);
/// do something
assert(pthread_spin_unlock(&my_lock) == 0);\
}while(0)
// main.cpp
#include "temp.h"
#define NUM_THREADS 5
void *logs(void *i){
int j;
for(j = 0 ; j < 10000 ; j++){
EXPAND_VAR(j, j+1);
}
std::cout << "returning from thread func" << std::endl;
pthread_exit(NULL);
}
int main(int argc, char* argv[]) {
int i;
pthread_t threads[NUM_THREADS];
for( i = 0; i < NUM_THREADS; i++) {
std::cout << " creating threads" << std::endl;
rc = pthread_create(&threads[i],NULL,logs,(void *)i);
}
std::cout << "returning from main" << std::endl;
pthread_exit(NULL);
return 0;
}
When executing the above code 'pthread_spin_lock' always gets blocked. I tried 'pthread_spin_trylock' and it passes with return value 0.
Anything i am missing that 'pthread_spin_lock' not working ?
I am using gcc version 4.1.2 :(
Related
This question already has answers here:
c++ multiple definitions of a variable
(5 answers)
multiple definition error c++
(2 answers)
What exactly is One Definition Rule in C++?
(1 answer)
Closed 2 years ago.
I am attempting to compile my c++ code, and I continue getting the error:
/tmp/ccEsZppG.o:(.bss+0x0): multiple definition of `mailboxes'
/tmp/ccEZq43v.o:(.bss+0x0): first defined here
/tmp/ccEsZppG.o:(.bss+0xc0): multiple definition of `threads'
/tmp/ccEZq43v.o:(.bss+0xc0): first defined here
/tmp/ccEsZppG.o:(.bss+0x120): multiple definition of `semaphores'
/tmp/ccEZq43v.o:(.bss+0x120): first defined here
collect2: error: ld returned 1 exit status
Here is my code:
addem.cpp
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include "mailbox.h"
using namespace std;
void *sumUp(void *arg);
int main(int argc, char *argv[]) {
int numThreads, minThreads, maxInt, minInt;
if (argc < 3) {
cout << "Error: Need three arguments" << endl;
return 1;
}
numThreads = atoi(argv[1]);
maxInt = atoi(argv[2]);
minThreads = 1;
minInt = 1;
if (numThreads < 1) {
cout << "Cannot work with less than one thread\n"
<< "It's okay but do better next time!\n"
<< "We'll work with 1 thread this time.\n";
numThreads = minThreads;
} else if (numThreads > MAXTHREAD) {
cout << "Sorry, the max for threads is 10.\n"
<< "We'll work with 10 threads this time.\n";
numThreads = MAXTHREAD;
}
if (maxInt < 1) {
cout << "What do you want me to do? I can't count backwards!\n"
<< "I can barely count forwards! Let's make the max number\n"
<< "be 1 to save time\n";
maxInt = minInt;
}
struct msg outgoingMail[numThreads];
int divider = maxInt / numThreads;
int count = 1;
//initialize arrays (mailboxes, semaphores)
for (int i = 0; i < numThreads; i++) {
sem_init(&semaphores[i], 0, 1);
outgoingMail[i].iSender = 0;
outgoingMail[i].type = RANGE;
outgoingMail[i].value1 = count;
count = count + divider;
if (i = numThreads - 1) {
outgoingMail[i].value2 = maxInt;
} else {
outgoingMail[i].value2 = count;
}
}
for (int message = 0; message < numThreads; message++) {
SendMsg(message+1, outgoingMail[message]);
}
int thread;
for (thread = 0; thread <= numThreads; thread++) {
pthread_create(&threads[thread], NULL, &sumUp, (void *)(intptr_t)(thread+1));
}
struct msg incomingMsg;
int total = 0;
for (thread = 0; thread < numThreads; thread++) {
RecvMsg(0, incomingMsg);
total = total + incomingMsg.value1;
}
cout << "The total for 1 to " << maxInt << " using "
<< numThreads << " threads is " << total << endl;
return 0;
}
void *sumUp(void *arg) {
int index,total;
index = (intptr_t)arg;
struct msg message;
RecvMsg(index, message);
message.iSender = index;
message.type = ALLDONE;
total = 0;
for (int i = message.value1; i <= message.value2; i++) {
total += i;
}
SendMsg(0, message);
return (void *) 0;
}
mailbox.cpp
#include <stdio.h>
#include <iostream>
#include "mailbox.h"
using namespace std;
int SendMsg(int iTo, struct msg &Msg) {
if (safeToCall(iTo)) {
cout << "Error calling SendMsg" << endl;
return 1;
}
sem_wait(&semaphores[iTo]);
mailboxes[iTo] = Msg;
sem_post(&semaphores[iTo]);
return 0;
}
int RecvMsg(int iFrom, struct msg &Msg) {
sem_wait(&semaphores[iFrom]);
if (safeToCall(iFrom)) {
cout << "Error calling RecvMsg" << endl;
return 1;
}
mailboxes[iFrom] = Msg;
sem_post(&semaphores[iFrom]);
return 0;
}
bool safeToCall(int location) {
bool safe = !(location < 0 || location > MAXTHREAD + 1);
return safe;
//return true;
}
mailbox.h
#ifndef MAILBOX_H_
#define MAILBOX_H_
#define RANGE 1
#define ALLDONE 2
#define MAXTHREAD 10
#include <semaphore.h>
#include <pthread.h>
struct msg {
int iSender; /* sender of the message (0 .. numThreads)*/
int type; /* its type */
int value1; /* first value */
int value2; /* second value */
};
struct msg mailboxes[MAXTHREAD + 1];
pthread_t threads[MAXTHREAD + 1];
sem_t semaphores[MAXTHREAD + 1];
int SendMsg(int iTo, struct msg &Msg);
int RecvMsg(int iFrom, struct msg &Msg);
bool safeToCall(int location);
#endif
I am compiling the code with the command
g++ -o addem addem.cpp mailbox.cpp -lpthread
I have tried commenting out all of the function bodies in the source code to leave them as stub functions, and the same error occurs. The only way I have been able to compile the file is if I comment out the function bodies, and remove
#include "mailbox.h"
From at least one of the files. I feel it has to do with how I am initializing the arrays? But I cannot figure out a workaround.
I've started working with libmemleak library and I tried getting the basic sample code to work.
I'm able to catch leaks but when trying to view the backtraces i get cryptic messages.
Using the hello.cc example for libmemleak, on one terminal running:
LD_PRELOAD='/usr/local/lib/libmemleak.so /usr/lib/x86_64-linux-gnu/libdl.so /usr/lib/x86_64-linux-gnu/libbfd.so' ./hello
On another terminal running:
./memleak_control
then
libmemleak>start
and
libmemleak>dump 49
Leaking sample code (hello.cc example from libmemleak repository):
#include <iostream>
#include <cstdlib>
#include <inttypes.h>
#include <deque>
#include <cstdio>
extern "C" {
#include "addr2line.h"
}
#ifdef DIRECT_LINKED
extern "C" void memleak_stats();
extern "C" void interval_restart_recording(void);
extern "C" void interval_stop_recording(void);
#endif
void do_work(bool leak);
void* thread_entry0(void*) { do_work(false); return NULL; }
void* thread_entry1(void*) { do_work(true); return NULL; }
void* thread_entry2(void*) { do_work(false); return NULL; }
void* thread_entry3(void*) { do_work(false); return NULL; }
void purge(void);
#ifdef DIRECT_LINKED
void* monitor(void*);
int quit = 0;
#endif
size_t leaked_mem = 0;
int main()
{
std::cout << "Entering main()" << std::endl;
#ifdef DIRECT_LINKED
memleak_stats();
#endif
int const threads = 4;
pthread_t thread[threads];
for (int i = 0; i < threads; ++i)
{
switch(i)
{
case 0:
pthread_create(&thread[0], NULL, &thread_entry0, NULL);
break;
case 1:
pthread_create(&thread[1], NULL, &thread_entry1, NULL);
break;
case 2:
pthread_create(&thread[2], NULL, &thread_entry2, NULL);
break;
case 3:
pthread_create(&thread[3], NULL, &thread_entry3, NULL);
break;
}
}
#ifdef DIRECT_LINKED
pthread_t monitor_thread;
pthread_create(&monitor_thread, NULL, &monitor, NULL);
#endif
for (int i = 0; i < threads; ++i)
pthread_join(thread[i], NULL);
std::cout << "All threads exited. Purging and terminating monitor thread." << std::endl;
purge();
#ifdef DIRECT_LINKED
quit = 1;
pthread_join(monitor_thread, NULL);
interval_stop_recording();
#endif
std::cout << "Deliberate number of missed calls to free(): " << leaked_mem << std::endl;
#ifdef DIRECT_LINKED
memleak_stats();
#endif
}
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
std::deque<void*> allocations;
void store(void* ptr)
{
if (!ptr)
return;
pthread_mutex_lock(&mutex);
allocations.push_back(ptr);
pthread_mutex_unlock(&mutex);
}
void* remove(void)
{
void* ret = NULL;
pthread_mutex_lock(&mutex);
if (!allocations.empty())
{
ret = allocations.front();
allocations.pop_front();
}
pthread_mutex_unlock(&mutex);
return ret;
}
void purge(void)
{
int count = 0;
pthread_mutex_lock(&mutex);
while (!allocations.empty())
{
free(allocations.front());
allocations.pop_front();
++count;
}
pthread_mutex_unlock(&mutex);
std::cout << "Purged " << count << " allocations." << std::endl;
}
void do_work(bool leak)
{
struct random_data rdata;
int32_t rvalue;
char rstatebuf[256];
initstate_r(0x1234aabc, rstatebuf, sizeof(rstatebuf), &rdata);
for (int i = 0; i < 1000000000; ++i)
{
random_r(&rdata, &rvalue);
rvalue >>= 8;
bool allocate = rvalue & 1;
int how = (rvalue >> 1) & 0x3;
size_t size = (rvalue >> 3) & 0xff;
bool leak_memory = leak && ((rvalue >> 19) & 0xfff) == 0;
if (!allocate)
{
void* ptr = remove();
if (!leak_memory)
{
free(ptr);
}
else if (ptr)
++leaked_mem;
}
else
{
if (how == 0)
store(realloc(remove(), size));
else if (how == 1)
store(calloc(13, size / 13));
else
store(malloc(size));
}
}
pthread_exit(0);
}
Actual:
libmemleak> dump 49
#0 00007f383ffa9d76 in malloc at /home/rfogel/workspace/libmemleak/src/memleak.c:1008
#1 00005587313eaa1a in "hello"
#2 00005587313eaa9e in "hello"
#3 00007f383efa64a4 in start_thread at /build/glibc-77giwP/glibc-2.24/nptl/pthread_create.c:456
#4 00007f383ece8d0f in ?? at /build/glibc-77giwP/glibc-2.24/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:99
Expected:
libmemleak> dump 49
#0 00007f84b862d33b in malloc at /home/carlo/projects/libmemleak/libmemleak-objdir/src/../../libmemleak/src/memleak.c:1008
#1 00000000004014da in do_work(int)
#2 000000000040101c in thread_entry0(void*)
#3 00007f84b7e7070a in start_thread
#4 00007f84b7b9f82d in ?? at /build/glibc-Qz8a69/glibc-2.23/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:99
I've reached out to the main developer for libmemleak and he fixed the relevant code in addr2line.c file inside the library code.
Link to the commit:
https://github.com/CarloWood/libmemleak/commit/ec1080cef9b33515c4e2472f1418c5bb75af1d96
It works perfectly now.
I am trying to communicate with forked child process using message queue from boost interprocess library. When child process calls receive it causes exception with message
boost::interprocess_exception::library_error
I am using GCC 6.3 on Debian 9 x64.
#include <iostream>
#include <unistd.h>
#include <boost/interprocess/ipc/message_queue.hpp>
#include <memory>
int main(int argc, char* argv[])
{
using namespace boost::interprocess;
const char* name = "foo-552b8ae9-6037-4b77-aa0d-d4dc9dad790b";
const int max_num_msg = 100;
const int max_msg_size = 32;
bool is_child = false;
message_queue::remove(name);
auto mq = std::make_unique<message_queue>(create_only, name, max_num_msg, max_msg_size);
auto child_pid = fork();
if (child_pid == -1)
{
std::cout << "fork failed" << std::endl;
return -1;
}
else if (child_pid == 0)
{
is_child = true;
}
if (is_child)
{
// does child needs to reopen it?
mq.reset( new message_queue(open_only, name) );
}
int send_num = 0;
while(true)
{
unsigned int priority = 0;
if (is_child)
{
message_queue::size_type bytes = 0;
try
{
int num;
// Always throws. What is wrong ???????
mq->receive(&num, sizeof(num), bytes, priority);
std::cout << num << std::endl;
}
catch(const std::exception& e)
{
std::cout << "Receive caused execption " << e.what() << std::endl;
}
sleep(1);
}
else
{
mq->send(&send_num, sizeof(send_num), priority);
send_num++;
sleep(5);
}
}
return 0;
}
Also, in child process is it required to reopen the message queue created by the parent process? I tried it both ways and neither worked. I am getting the same exception on receive.
The problem is that your receive buffer is smaller than max_msg_size. Assuming 4-byte integers, this should work:
int num[8];
mq.receive(num, sizeof(num), bytes, priority);
std::cout << *num << std::endl;
Also, I see no reason to play fast and loose with the actual queue instance. Just create it per process:
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <iostream>
#include <memory>
#include <unistd.h>
int main() {
namespace bip = boost::interprocess;
const char *name = "foo-552b8ae9-6037-4b77-aa0d-d4dc9dad790b";
{
const int max_num_msg = 100;
const int max_msg_size = 32;
bip::message_queue::remove(name);
bip::message_queue mq(bip::create_only, name, max_num_msg, max_msg_size);
}
auto child_pid = fork();
if (child_pid == -1) {
std::cout << "fork failed" << std::endl;
return -1;
}
bip::message_queue mq(bip::open_only, name);
if (bool const is_child = (child_pid == 0)) {
while (true) {
unsigned int priority = 0;
bip::message_queue::size_type bytes = 0;
try {
int num[8];
mq.receive(num, sizeof(num), bytes, priority);
std::cout << *num << std::endl;
} catch (const bip::interprocess_exception &e) {
std::cout << "Receive caused execption " << boost::diagnostic_information(e, true) << std::endl;
}
sleep(1);
}
} else {
// parent
int send_num = 0;
while (true) {
unsigned int priority = 0;
mq.send(&send_num, sizeof(send_num), priority);
send_num++;
sleep(5);
}
}
}
My application start the logThread thread and then cyclically calls lookForSms wich makes a curl call and wait for logThread to read a certain string, but this string may never come so i used a condition_variable wait_for so that eventually (after 5 minutes) it can continue the test.
The problem is at times it waits a lot longer, sometimes 20 min sometimes forever.
How can I make it reliably work?
I'm using Visual Studio Community 2017, here the code:
void lookForSms(CURL *curl) {
sms_found = false;
int i;
CURLcode res;
cout << "\n" << timestamp() << "\t";
res = curl_easy_perform(curl);
if (res == CURLE_OK) {
unique_lock<mutex> lk(F);
analysis << timestampMil() << "\t";
while (cv.wait_for(lk, TIMEOUT_SMS * 1000ms) != cv_status::timeout && !sms_found);
if (sms_found) {
analysis << timestampMil() << "\tSMS RECEIVED\n";
cout << "\tOK";
}
else {
analysis << timestampMil() << "\tSMS LOST\n";
cout << "\tKO";
}
}
}
void logThread() {
string line;
int n, i, count;
unsigned char buf[BUFFER];
while (!close) {
N.lock();
M.lock();
N.unlock();
n = RS232_PollComport(comport, buf, BUFFER);
if (n > 0 && n < BUFFER) {
buf[n] = '\0';
for (i = 0; i < n; i++) {
if (buf[i] == '\n') {
all << timestampMil() << "\t" << line << "\n";
handleLine(line);
line = string();
}
else if (buf[i] != '\r' && buf[i] >= 32) {
line += buf[i];
}
}
}
M.unlock();
}
}
void handleLine(string line) {
if (searchString(line, RCV_SMS)) {
unique_lock<mutex> lk(F);
sms_found = true;
lk.unlock();
cv.notify_all();
}
}
[EDIT] This should have everything it needs to recreate the problem.
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#define TIMEOUT_SMS 300
#define DELAY_SMS 10
mutex L, M, N, F;
condition_variable cv;
void logThread() {
while (!close) {
N.lock();
M.lock();
N.unlock();
handleLine("");
Sleep(500);
M.unlock();
}
}
void lookForSms() {
unique_lock<mutex> lk(F);
sms_found = false;
unlocked = false;
//while (cv.wait_for(lk, TIMEOUT_SMS * 1000ms) != cv_status::timeout && !unlocked);
cv.wait_for(lk, 10 * TIMEOUT_SMS * 1000ms, []() {return unlocked; });
if (sms_found) {
cout << "\tOK";
}
else {
cout << "\tKO";
}
}
}
void handleLine(string line) {
if (false) {// the problem is when cv remains locked
unique_lock<mutex> lk(F);
unlocked = true;
sms_found = true;
lk.unlock();
cv.notify_all();
}
}
void stopThreads() {
N.lock();
M.lock();
//stop log thread
close = true;
N.unlock();
M.unlock();
}
int main(int argc, const char * argv[]) {
thread logger(logThread);
for (i = 0; i < repeat; i++) {
lookForSms();
Sleep(DELAY_SMS * 1000);
}
//aquire mutex and set close to true, then join
stopThreads();
//wait for the thread to end
logger.join();
return 0;
}
I wrote a code to implement spin lock and mutex lock.
There is an interesting but. A magic cout can keep my program alive. If I remove the cout, my program will be sleeping forever. (This only happens in Linux. Windows is doing fine)
Any one have a clue?
#include <pthread.h>
#include <iostream>
#include <queue>
#include <sys/time.h>
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
using namespace std;
#define Tcount 10
#define TheLock MutexLock
static inline int TAS(volatile int * ptr) {
unsigned long result;
asm volatile("lock;"
"xchgl %0, %1;"
: "=r"(result), "=m"(*ptr)
: "0"(1), "m"(*ptr)
: "memory");
return result;
}
class SpinLock {
private:
int lock;
pthread_t owner;
public:
SpinLock() {
lock = 0;
}
void getLock() {
while (TAS(&lock) == 1) {
}
owner = pthread_self();
}
void releaseLock() {
if (lock == 0) {
cout << "Spin no lock" << endl;
return;
} else if (owner == pthread_self()) {
owner = NULL;
lock = 0;
} else {
throw runtime_error("Spin can't release");
}
}
};
class MutexLock {
private:
int lock;
pthread_t owner;
queue<pthread_t> q;
SpinLock qLock;
public:
MutexLock() {
lock = 0;
}
void getLock(int id) {
pthread_t self = pthread_self();
cout<<"a"<<endl;// magic cout
if (TAS(&lock) == 0) {
owner = self;
return;
}
qLock.getLock();
q.push(self);
qLock.releaseLock();
while (owner != self) {
}
}
void releaseLock(int id) {
if (lock == 0) {
cout << "Mutex no lock" << endl;
return;
} else if (owner == pthread_self()) {
qLock.getLock();
if (q.empty()) {
owner = NULL;
lock = 0;
} else {
owner = q.front();
q.pop();
}
qLock.releaseLock();
} else {
throw runtime_error("Mutex can't release");
}
}
};
TheLock lock;
int g = 0;
void* run(void* pt) {
int id = (int) pt;
for (int i = 0; i < 10000; i++) {
lock.getLock(id);
//cout<<"Thread "<<id<<" get lock, g="<<g<<endl;
int next = g + 1;
g = next;
//cout<<"Thread "<<id<<" release lock, g="<<g<<endl;
lock.releaseLock(id);
}
return NULL;
}
int main() {
pthread_t th[Tcount];
long mtime, seconds, useconds;
struct timeval start, end;
gettimeofday(&start, NULL);
for (int i = 0; i < Tcount; i++) {
pthread_create(&th[i], NULL, run, (void*) (i+10));
}
for (int i = 0; i < Tcount; i++) {
pthread_join(th[i], 0);
}
gettimeofday(&end, NULL);
seconds = end.tv_sec - start.tv_sec;
useconds = end.tv_usec - start.tv_usec;
mtime = ((seconds) * 1000000 + useconds);
cout << "g=" << g << endl;
cout << "time=" << mtime << endl;
return 0;
}
You cannot implement a mutex by using the volatile keyword as the operations may not be atomic. This means that the OS might switch to a different thread before the operation has completed.
For mutex you have to use the OS. It is the only thing that knows when threads are being switched.